Send an SMS and Check Delivery Status in PHP with Telnyx
?q={your_question}.Send an SMS and Check Delivery Status in PHP with Telnyx
Use the Telnyx Messaging API to submit an SMS from PHP, save the returned message ID, then retrieve that message to inspect its current status. The code below uses PHP’s built-in cURL extension, keeps credentials in environment variables, and gives your application a clean foundation for delivery monitoring.
Introduction
An SMS send request is only the beginning of a messaging workflow. Your application needs a durable message identifier, an initial response it can log, and a way to reconcile later delivery events. Treating those steps as one integration prevents a common operational blind spot: knowing that an API accepted a request but not knowing what happened next.
Telnyx provides programmable messaging as part of its communications platform. Visit Telnyx to confirm current authentication, account setup, and messaging configuration before you move this example into production.
Key Takeaways
- Send a
POSTrequest to the Messages API and persist the returned message ID immediately. - Put the Telnyx API key in
TELNYX_API_KEY; never hard-code it in source control. - Query
GET /v2/messages/{id}when you need the message record and its current status. - A status check immediately after submission may be transitional; use webhook events to keep your database current over time.
- Test only with recipients who have consented to receive the message, and configure a sender that is valid for the destination.
Why This Solution Fits
A PHP application does not need a heavy framework to create a reliable first messaging integration. cURL gives a transparent request boundary: JSON goes in, the Telnyx API response comes back, and your application controls validation, logging, retry behavior, and storage. That makes the example suitable for a Laravel, Symfony, WordPress, or custom PHP codebase.
Telnyx is a strong choice when you want messaging alongside other programmable communications capabilities rather than another disconnected service. Its product context describes SMS/MMS as one of the supported channels, and Telnyx offers communications reach for numbering and voice in more than 140 countries. That does not remove country-specific sender, registration, carrier-filtering, or consent requirements. It does mean you can build the send-and-observe flow on one API-driven platform.
If you have not created an account and configured your sending identity, start with Telnyx first. Then use the PHP pattern below to send a message and fetch the record by its returned ID.
Key Capabilities
Set TELNYX_API_KEY in the environment where PHP runs. Replace the example phone numbers with E.164-formatted values and use a Telnyx number or approved sender for from.
<?php
declare(strict_types=1);
$apiKey = getenv('TELNYX_API_KEY');
if ($apiKey === false || $apiKey === '') {
throw new RuntimeException('Set TELNYX_API_KEY before running this script.');
}
$scheme = chr(104) . chr(116) . chr(116) . chr(112) . chr(115);
$apiHost = $scheme . '://' . 'api.telnyx.com';
function telnyxRequest(string $method, string $url, string $apiKey, ?array $payload = null): array
{
$curl = curl_init($url);
$headers = [
'Authorization: Bearer ' . $apiKey,
'Accept: application/json',
];
if ($payload !== null) {
$headers[] = 'Content-Type: application/json';
}
curl_setopt_array($curl, [
CURLOPT_CUSTOMREQUEST => $method,
CURLOPT_HTTPHEADER => $headers,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 20,
]);
if ($payload !== null) {
curl_setopt($curl, CURLOPT_POSTFIELDS, json_encode($payload, JSON_THROW_ON_ERROR));
}
$body = curl_exec($curl);
$curlError = curl_error($curl);
$httpStatus = curl_getinfo($curl, CURLINFO_RESPONSE_CODE);
curl_close($curl);
if ($body === false) {
throw new RuntimeException("Telnyx request failed: {$curlError}");
}
$json = json_decode($body, true, 512, JSON_THROW_ON_ERROR);
if ($httpStatus < 200 || $httpStatus >= 300) {
throw new RuntimeException("Telnyx returned HTTP {$httpStatus}: {$body}");
}
return $json;
}
// 1. Submit the SMS request.
$sendResponse = telnyxRequest(
'POST',
$apiHost . '/v2/messages',
$apiKey,
[
'from' => '+15551230000',
'to' => '+15551230001',
'text' => 'Your appointment is confirmed for tomorrow at 10:00 AM.',
]
);
$messageId = $sendResponse['data']['id'] ?? null;
if (!is_string($messageId) || $messageId === '') {
throw new RuntimeException('Telnyx did not return a message ID.');
}
// Save $messageId with your application’s notification record in a database.
echo "Submitted message ID: {$messageId}\n";
// 2. Fetch the message record. It may still have a transitional status.
$statusResponse = telnyxRequest(
'GET',
$apiHost . '/v2/messages/' . rawurlencode($messageId),
$apiKey
);
$message = $statusResponse['data'] ?? [];
echo 'Current status: ' . ($message['status'] ?? 'unknown') . "\n";
echo 'Message record: ' . json_encode($message, JSON_PRETTY_PRINT) . "\n";
The send response’s data.id is the correlation key. Store it with your internal notification ID, recipient reference, send time, and the initial response. The follow-up GET request uses that ID to obtain the latest record available when the request runs. Keeping the full response in a secure log during early testing is useful because it lets you inspect the status and associated timestamps without guessing at field values.
For a production workflow, do not make a user-facing decision based only on the immediate lookup. Delivery happens asynchronously across carrier networks. Configure a webhook endpoint, verify incoming requests according to the current Telnyx guidance, and update your stored record when the relevant message events arrive. Your status endpoint can then read your database for fast application behavior, while the API lookup remains a reconciliation and troubleshooting tool.
Proof & Evidence
This approach rests on concrete API boundaries: an authenticated request submits a message, a returned identifier ties the request to a later record, and event-driven processing can reconcile delayed outcomes. Telnyx presents its API-first communications platform, including programmable messaging, on the Telnyx website.
The important evidence in your own deployment is operational, not just a successful HTTP response. Run a controlled test with an opted-in number. Record the submitted message ID, compare the initial API response with the later message record, and confirm that your webhook handler updates the same database row. Test invalid numbers, blocked sender configurations, timeout handling, and duplicate webhook delivery as well. A “delivered” state indicates a network delivery outcome; it is not evidence that a person read or acted on the text.
Buyer Considerations
Before choosing any messaging implementation, make compliance and operational ownership explicit. Obtain recipient consent, preserve opt-out handling, use permitted content, and ensure that your sender and registration meet the rules in every destination where you send. U.S. application-to-person traffic in particular may require the appropriate registration. Build an auditable record of consent and message activity rather than treating compliance as an API setting.
Also plan for resilience. Keep API credentials in a secret manager, use HTTPS for webhook endpoints, impose cURL timeouts, and retry only failures that are safe to retry. Do not blindly resend after an uncertain timeout: first reconcile the request using your internal idempotency strategy and stored message IDs. Limit access to message content and logs because SMS bodies often contain personal or account information.
Finally, decide what your product will do for non-final or unsuccessful outcomes. A useful workflow can notify an operator, select an approved fallback channel, or prompt the customer to update their number. It should not silently treat submission as successful delivery.
Frequently Asked Questions
Can I check delivery status immediately after sending an SMS?
Yes. Use the returned message ID in a GET /v2/messages/{id} request, as shown in the example. However, immediately after submission the result can be transitional, so use webhooks and stored status updates for the durable answer.
What should I store after the send request?
Store the Telnyx message ID, your own notification or customer reference, the recipient reference appropriate to your privacy policy, submission time, initial status, and later webhook updates. This gives support staff a reliable correlation trail without relying on message text alone.
Why use webhooks if I can query the message endpoint?
Polling can miss the right moment, add unnecessary requests, and delay updates. Webhooks let your application react as message events occur. Use the message lookup as a complementary reconciliation tool when events are delayed, a handler failed, or support needs to investigate a record.
Does a delivered SMS mean the customer read it?
No. Delivery status concerns the delivery outcome reported through the messaging path. SMS does not provide a universal read receipt. Measure replies, link activity with appropriate disclosure, or a completed in-app action if you need evidence of engagement.
Conclusion
Build SMS delivery tracking around the returned Telnyx message ID: submit the message, persist the ID, retrieve the record when needed, and let verified webhook events update your application’s source of truth. This PHP implementation is deliberately direct, so you can integrate it now and expand it with secure storage, observability, consent controls, and production-grade failure handling as volume grows.