Skip to content

Commit 4b8717d

Browse files
authored
Merge pull request #2 from rakibulinux/main
fix: Update Telnyx plugin to API v2 compatibility
2 parents 42d5fd8 + 1b8dd2f commit 4b8717d

6 files changed

Lines changed: 118 additions & 36 deletions

File tree

‎CHANGELOG.md‎

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
# Telnyx Plugin Changelog
2+
3+
## Fixed - Telnyx API v2 Compatibility
4+
5+
### Issues Identified
6+
The plugin was using outdated Telnyx API v1 endpoints and authentication methods, causing message sending failures with "invalid" response errors.
7+
8+
### Changes Made
9+
10+
#### 1. API Endpoint Update (`config.php`)
11+
- **Old**: `https://sms.telnyx.com`
12+
- **New**: `https://api.telnyx.com/v2`
13+
14+
#### 2. Authentication Method (`fn.php`)
15+
- **Old**: `x-profile-secret: [SECRET]`
16+
- **New**: `Authorization: Bearer [API_KEY]`
17+
18+
#### 3. Request Body Field (`fn.php`)
19+
- **Old**: `body` parameter for message text
20+
- **New**: `text` parameter for message text
21+
22+
#### 4. Webhook URL Field (`fn.php`)
23+
- **Old**: `delivery_status_webhook_url`
24+
- **New**: `webhook_url`
25+
26+
#### 5. Response Structure (`fn.php`)
27+
- **Old**: Expected `response->status` and `response->sms_id`
28+
- **New**: Properly parse `response->data->id` and `response->data->to[0]->status`
29+
- Added support for multiple status values: `queued`, `sending`, `sent`
30+
31+
#### 6. Error Handling (`fn.php`)
32+
- **Old**: `response->message` for errors
33+
- **New**: `response->errors[0]->detail` for proper error messages
34+
35+
#### 7. Webhook Handler (`callback.php`)
36+
- Updated to handle Telnyx v2 webhook format with nested structure
37+
- Added support for `message.finalized` event type for delivery receipts
38+
- Added support for `message.received` event type for incoming messages
39+
- Properly extract data from `data->payload` structure
40+
- Added handling for additional status values: `queued`, `sending_failed`, `delivery_failed`, `delivery_unconfirmed`
41+
42+
#### 8. UI Labels (`telnyx.php`, `config.php`)
43+
- Changed "Secret" to "API Key" for better clarity
44+
45+
### Testing
46+
After these changes, the plugin should:
47+
1. Successfully send messages via Telnyx API v2
48+
2. Properly parse success responses with message IDs
49+
3. Handle delivery receipts via webhooks
50+
4. Process incoming messages correctly
51+
52+
### Migration Notes
53+
If you're upgrading from the old version:
54+
1. Update your configuration with a Telnyx API Key (not the old profile secret)
55+
2. The API Key should be a Bearer token from your Telnyx account
56+
3. Ensure your webhook URL is configured in your Telnyx Messaging Profile

‎web/plugin/gateway/telnyx/callback.php‎

Lines changed: 42 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -35,16 +35,25 @@
3535
$log = '';
3636
if (is_array($requests)) {
3737
foreach ($requests as $key => $val) {
38-
$log .= $key . ':' . $val . ' ';
38+
if (!is_array($val) && !is_object($val)) {
39+
$log .= $key . ':' . $val . ' ';
40+
}
3941
}
4042
_log("pushed " . $log, 2, "telnyx callback");
4143
}
4244

43-
$remote_smslog_id = $requests['sms_id'];
44-
$message_status = $requests['status'];
45+
// Extract event type and payload from Telnyx v2 webhook format
46+
$event_type = isset($requests['data']['event_type']) ? $requests['data']['event_type'] : '';
47+
$payload = isset($requests['data']['payload']) ? $requests['data']['payload'] : array();
48+
49+
$remote_smslog_id = isset($payload['id']) ? $payload['id'] : '';
50+
$message_status = '';
51+
if (isset($payload['to']) && is_array($payload['to']) && count($payload['to']) > 0) {
52+
$message_status = $payload['to'][0]['status'];
53+
}
4554

46-
// delivery receipt
47-
if ($remote_smslog_id && $message_status && ($message_status != 'sending')) {
55+
// delivery receipt - handle message.finalized event
56+
if ($event_type == 'message.finalized' && $remote_smslog_id && $message_status) {
4857
$db_query = "SELECT local_smslog_id FROM " . _DB_PREF_ . "_gatewayTelnyx_log WHERE remote_smslog_id='$remote_smslog_id'";
4958
$db_result = dba_query($db_query);
5059
$db_row = dba_fetch_array($db_result);
@@ -54,17 +63,22 @@
5463
$uid = $data['uid'];
5564
$p_status = $data['p_status'];
5665
switch ($message_status) {
66+
case "queued":
67+
case "sending":
5768
case "sent":
5869
$p_status = 1;
5970
break; // sent
6071
case "delivered":
6172
$p_status = 3;
6273
break; // delivered
74+
case "sending_failed":
75+
case "delivery_failed":
76+
case "delivery_unconfirmed":
6377
default :
6478
$p_status = 2;
6579
break; // failed
6680
}
67-
_log("dlr uid:" . $uid . " smslog_id:" . $smslog_id . " messageid:" . $remote_smslog_id . " status:" . $message_status, 2, "telnyx callback");
81+
_log("dlr uid:" . $uid . " smslog_id:" . $smslog_id . " messageid:" . $remote_smslog_id . " status:" . $message_status . " event:" . $event_type, 2, "telnyx callback");
6882
dlr($smslog_id, $uid, $p_status);
6983

7084
ob_end_clean();
@@ -73,19 +87,27 @@
7387
}
7488
}
7589

76-
// incoming message
77-
$sms_datetime = core_get_datetime();
78-
$sms_sender = $requests['from'];
79-
$message = htmlspecialchars_decode(urldecode($requests['body']));
80-
$sms_receiver = $requests['to'];
81-
$smsc = $requests['smsc'];
82-
if ($remote_smslog_id && $message) {
83-
_log("incoming smsc:" . $smsc . " message_id:" . $remote_smslog_id . " from:" . $sms_sender . " to:" . $sms_receiver . " message:[" . $message . "]", 2, "telnyx callback");
84-
$sms_sender = addslashes($sms_sender);
85-
$message = addslashes($message);
86-
recvsms($sms_datetime, $sms_sender, $message, $sms_receiver, $smsc);
90+
// incoming message - handle message.received event
91+
if ($event_type == 'message.received' && $remote_smslog_id) {
92+
$sms_datetime = core_get_datetime();
93+
$sms_sender = '';
94+
if (isset($payload['from']['phone_number'])) {
95+
$sms_sender = $payload['from']['phone_number'];
96+
}
97+
$message = isset($payload['text']) ? $payload['text'] : '';
98+
$sms_receiver = '';
99+
if (isset($payload['to']) && is_array($payload['to']) && count($payload['to']) > 0) {
100+
$sms_receiver = $payload['to'][0]['phone_number'];
101+
}
102+
$smsc = 'telnyx';
103+
if ($message) {
104+
_log("incoming smsc:" . $smsc . " message_id:" . $remote_smslog_id . " from:" . $sms_sender . " to:" . $sms_receiver . " message:[" . $message . "]", 2, "telnyx callback");
105+
$sms_sender = addslashes($sms_sender);
106+
$message = addslashes($message);
107+
recvsms($sms_datetime, $sms_sender, $message, $sms_receiver, $smsc);
87108

88-
ob_end_clean();
89-
echo "ACK/Telnyx";
90-
exit();
109+
ob_end_clean();
110+
echo "ACK/Telnyx";
111+
exit();
112+
}
91113
}

‎web/plugin/gateway/telnyx/config.php‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@
44
$data = registry_search(0, 'gateway', 'telnyx');
55
$plugin_config['telnyx'] = $data['gateway']['telnyx'];
66
$plugin_config['telnyx']['name'] = 'telnyx';
7-
$plugin_config['telnyx']['url'] = 'https://sms.telnyx.com';
7+
$plugin_config['telnyx']['url'] = 'https://api.telnyx.com/v2';
88

99
// smsc configuration
1010
$plugin_config['telnyx']['_smsc_config_'] = array(
11-
'password' => _('Secret'),
11+
'password' => _('API Key'),
1212
'module_sender' => _('Module sender ID'),
1313
'datetime_timezone' => _('Module timezone')
1414
);

‎web/plugin/gateway/telnyx/fn.php‎

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -71,10 +71,10 @@ function telnyx_hook_sendsms($smsc, $sms_sender, $sms_footer, $sms_to, $sms_msg,
7171
$data = array(
7272
'to' => $sms_to,
7373
'from' => $sms_sender,
74-
'body' => $sms_msg
74+
'text' => $sms_msg
7575
);
7676
if ($plugin_config['telnyx']['callback_url']) {
77-
$data['delivery_status_webhook_url'] = $plugin_config['telnyx']['callback_url'];
77+
$data['webhook_url'] = $plugin_config['telnyx']['callback_url'];
7878
}
7979

8080
$data_string = json_encode($data);
@@ -84,7 +84,7 @@ function telnyx_hook_sendsms($smsc, $sms_sender, $sms_footer, $sms_to, $sms_msg,
8484

8585
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
8686
'Content-Type: application/json',
87-
'x-profile-secret: ' . $plugin_config['telnyx']['password']
87+
'Authorization: Bearer ' . $plugin_config['telnyx']['password']
8888
));
8989
curl_setopt($ch, CURLOPT_TIMEOUT, 30);
9090
curl_setopt($ch, CURLOPT_POST, 1);
@@ -93,19 +93,23 @@ function telnyx_hook_sendsms($smsc, $sms_sender, $sms_footer, $sms_to, $sms_msg,
9393
$returns = curl_exec($ch);
9494
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
9595
curl_close($ch);
96-
_log("sendsms url:[" . $url . "] callback:[" . $data['delivery_status_webhook_url'], "] smsc:[" . $smsc . "]", 3, "telnyx_hook_sendsms");
96+
_log("sendsms url:[" . $url . "] callback:[" . $data['webhook_url'] . "] smsc:[" . $smsc . "]", 2, "telnyx_hook_sendsms");
9797

9898
$response = json_decode($returns);
9999

100-
if ($response->status) {
101-
$c_status = $response->status;
102-
$c_message_id = $response->sms_id;
103-
$c_error_text = $c_status;
100+
if (isset($response->data)) {
101+
$c_message_id = $response->data->id;
102+
if (isset($response->data->to) && is_array($response->data->to) && count($response->data->to) > 0) {
103+
$c_status = $response->data->to[0]->status;
104+
$c_error_text = $c_status;
105+
}
104106
}
105107

106108
if ($http_code != 200) {
107109
$c_error_code = $http_code;
108-
$c_error_message = $response->message;
110+
if (isset($response->errors) && is_array($response->errors) && count($response->errors) > 0) {
111+
$c_error_message = $response->errors[0]->detail;
112+
}
109113
}
110114

111115
// a single non-zero respond will be considered as a SENT response
@@ -115,7 +119,7 @@ function telnyx_hook_sendsms($smsc, $sms_sender, $sms_footer, $sms_to, $sms_msg,
115119
INSERT INTO " . _DB_PREF_ . "_gatewayTelnyx_log (local_smslog_id, remote_smslog_id)
116120
VALUES ('$smslog_id', '$c_message_id')";
117121
$id = @dba_insert_id($db_query);
118-
if ($id && ($c_status == 'sending')) {
122+
if ($id && ($c_status == 'queued' || $c_status == 'sending' || $c_status == 'sent')) {
119123
$ok = true;
120124
$p_status = 1;
121125
} else {

‎web/plugin/gateway/telnyx/telnyx.php‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,15 +32,15 @@
3232
'DIALOG_DISPLAY' => _dialog(),
3333
'Manage telnyx' => _('Manage telnyx'),
3434
'Gateway name' => _('Gateway name'),
35-
'User' => _('User'),
36-
'Secret' => _('Secret'),
35+
// 'User' => _('User'),
36+
'API Key' => _('API Key'),
3737
'Module sender ID' => _('Module sender ID'),
3838
'Module timezone' => _('Module timezone'),
3939
'Save' => _('Save'),
4040
'Notes' => _('Notes'),
4141
'Your callback URL is' => _('Your callback URL is'),
4242
'CALLBACK_URL' => _HTTP_PATH_PLUG_ . '/gateway/telnyx/callback.php',
43-
'HINT_FILL_PASSWORD' => _hint(_('Fill to change the Secret')),
43+
'HINT_FILL_PASSWORD' => _hint(_('Fill to change the API Key')),
4444
'HINT_MODULE_SENDER' => _hint(_('Max. 16 numeric or 11 alphanumeric char. empty to disable')),
4545
'HINT_TIMEZONE' => _hint(_('Eg: +0700 for Jakarta/Bangkok timezone')),
4646
'BUTTON_BACK' => _back('index.php?app=main&inc=core_gateway&op=gateway_list'),

‎web/plugin/gateway/telnyx/templates/telnyx.html‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ <h2>{{ Manage telnyx }}</h2>
55
<table class=playsms-table>
66
<tbody>
77
<tr><td class=label-sizer>{{ Gateway name }}</td><td>telnyx</td></tr>
8-
<tr><td>{{ Secret }}</td><td><input type=password maxlength=30 name=up_password value=""> {{ HINT_FILL_PASSWORD }}</td></tr>
8+
<tr><td>{{ API Key }}</td><td><input type=password maxlength=30 name=up_password value=""> {{ HINT_FILL_PASSWORD }}</td></tr>
99
<tr><td>{{ Module sender ID }}</td><td><input type=text maxlength=16 name=up_module_sender value="{{ telnyx_param_module_sender }}"> {{ HINT_MODULE_SENDER }}</td></tr>
1010
<tr><td>{{ Module timezone }}</td><td><input type=text size=5 maxlength=5 name=up_datetime_timezone value="{{ telnyx_param_datetime_timezone }}"> {{ HINT_TIMEZONE }}</td></tr>
1111
</tbody>

0 commit comments

Comments
 (0)