references https://github.com/signalwire/cloud-product/issues/18113
Background
Customers can create outbound RELAY messages using the api/messaging/messages API, and outbound SWML calls using the api/calling/calls API.
What Changed?
Customers can now pass a custom_variables object during the request for both endpoints in order to make them available during later lifecycle events.
Outbound Messages
When an outbound message request contains status_callback and custom_variables, the custom_variables will be appended to the callback event body.
Request:
curl --location 'https://SPACE.signalwire.com/api/messaging/messages' \
--header 'Content-Type: application/json' \
--header 'Authorization: Basic l' \
--data '{
"from": "+12223334444",
"to": "+12223334445",
"body": "[SignalWire Message]",
"status_callback": "https://webhook.site/95fc84f8-95e3-46bc-a1a5-9d1fa6fab117",
"custom_variables": {
"id": "12345",
"case_number": "54321"
}
}'
Status Callback Event
{
"id": "243ddb26-10e7-48e5-a518-a0edc283555d",
"project_id": "243ddb26-10e7-48e5-a518-a0edc283555d",
"status": "delivered",
"to": "+12223334445",
"from": "+12223334444",
"body": "[SignalWire Message]",
"number_of_segments": 1,
"timestamp": "2026-05-29T16:35:57Z",
"error_code": null,
"error_message": null,
"custom_variables": {
"id": "12345",
"case_number": "54321"
}
}
Outbound SWML Calls
When an outbound call is placed with a SWML document, the custom_variables will be appended to the POST body when the call answers and the SWML document is fetched.
Request:
curl --location 'https://SPACE.signalwire.com/api/calling/calls' \
--header 'Content-Type: application/json' \
--header 'Authorization: Basic ' \
--data '{
"command": "dial",
"params": {
"url": "https://path_to_swml_document.com",
"from": "+12223334444",
"to": "+12223334445",
"status_url": "https://webhook.site/95fc84f8-95e3-46bc-a1a5-9d1fa6fab117",
"custom_variables": {
"id": "12345",
"case_number": "54321"
}
}
}'
Webhook Event on Document Fetch
{
"call": {
"call_id": "8923fdbe-9d39-42b6-9af2-e69a1832eab3",
"node_id": "8923fdbe-9d39-42b6-9af2-e69a1832eab3",
"segment_id": "8923fdbe-9d39-42b6-9af2-e69a1832eab3",
"call_state": "answered",
"direction": "outbound",
"type": "phone",
"from": "+12223334444",
"to": "+12223334445",
"from_number": "+12223334444",
"to_number": "+12223334445",
"headers": [],
"dial_winner": "true",
"project_id": "243ddb26-10e7-48e5-a518-a0edc283555d",
"space_id": "243ddb26-10e7-48e5-a518-a0edc283555d"
},
"vars": {},
"envs": {
"id": "12345",
"case_number": "54321"
}
}
Validations
| Requirement |
Rule |
| Key format |
Keys must match ^[A-Za-z_][A-Za-z0-9_]*$ - they must start with a letter or underscore, and contain only letters, numbers, and underscores. |
| Reserved prefixes |
Keys cannot begin with signalwire_, sw_, rtc_, or internal_ (case-insensitive). These prefixes are reserved for internal use. |
| Maximum keys |
A maximum of 20 keys is allowed. |
| Value size |
Each value can be at most 1024 bytes. |
| Value type |
Values must be non-empty strings. |
Case sensitivity
Variable keys are case-sensitive. Per-call variables take precedence over pre-provisioned user variables - but only when their keys match exactly, including case.
If the keys differ in case, they are treated as two distinct variables and both are retained. For example, if a pre-provisioned variable is named GREETING and a per-call variable is named greeting, both will be present in the resulting user variables.
Errors
We have a few new codes for these params:
| Code |
Message |
must_be_object |
must be an object of string key/value pairs |
too_many_custom_variables |
must contain at most %{max} custom variables |
invalid_custom_variable_name |
custom variable name %{name} must start with a letter or underscore and contain only letters, numbers, and underscores |
reserved_custom_variable_name |
custom variable name %{name} uses a reserved prefix and cannot be set by the caller |
invalid_custom_variable_value |
custom variable %{name} value must be a non-empty string |
custom_variable_value_too_long |
custom variable %{name} value must be at most %{max} bytes |
Also, there was a code the previously had two messages but the same code - one was general, and one was specific to messaging. This was causing conflicts, so the original insufficient_balance code will remain with the message "Insufficient account balance", and the messaging specific one was renamed.
| Code |
Message |
insufficient_balance_to_receive_message |
Insufficient Account Balance to receive message. |
What needs updates?
https://signalwire.com/docs/apis/rest/calls/call-commands
https://signalwire.com/docs/apis/rest/messages/create-message
https://signalwire.com/docs/apis/error-codes#error-code-reference
Notes
This will roll out to production global on June 1st, barring any issues with the planned deployment.
Please feel free to reach out with any questions!
references https://github.com/signalwire/cloud-product/issues/18113
Background
Customers can create outbound RELAY messages using the
api/messaging/messagesAPI, and outbound SWML calls using theapi/calling/callsAPI.What Changed?
Customers can now pass a
custom_variablesobject during the request for both endpoints in order to make them available during later lifecycle events.Outbound Messages
When an outbound message request contains
status_callbackandcustom_variables, thecustom_variableswill be appended to the callback event body.Request:
Status Callback Event
Outbound SWML Calls
When an outbound call is placed with a SWML document, the
custom_variableswill be appended to the POST body when the call answers and the SWML document is fetched.Request:
Webhook Event on Document Fetch
Validations
^[A-Za-z_][A-Za-z0-9_]*$- they must start with a letter or underscore, and contain only letters, numbers, and underscores.signalwire_,sw_,rtc_, orinternal_(case-insensitive). These prefixes are reserved for internal use.Case sensitivity
Variable keys are case-sensitive. Per-call variables take precedence over pre-provisioned user variables - but only when their keys match exactly, including case.
If the keys differ in case, they are treated as two distinct variables and both are retained. For example, if a pre-provisioned variable is named
GREETINGand a per-call variable is namedgreeting, both will be present in the resulting user variables.Errors
We have a few new codes for these params:
must_be_objecttoo_many_custom_variables%{max}custom variablesinvalid_custom_variable_name%{name}must start with a letter or underscore and contain only letters, numbers, and underscoresreserved_custom_variable_name%{name}uses a reserved prefix and cannot be set by the callerinvalid_custom_variable_value%{name}value must be a non-empty stringcustom_variable_value_too_long%{name}value must be at most%{max}bytesAlso, there was a code the previously had two messages but the same code - one was general, and one was specific to messaging. This was causing conflicts, so the original
insufficient_balancecode will remain with the message "Insufficient account balance", and the messaging specific one was renamed.insufficient_balance_to_receive_messageWhat needs updates?
https://signalwire.com/docs/apis/rest/calls/call-commands
https://signalwire.com/docs/apis/rest/messages/create-message
https://signalwire.com/docs/apis/error-codes#error-code-reference
Notes
This will roll out to production global on June 1st, barring any issues with the planned deployment.
Please feel free to reach out with any questions!