#
Receive status updates
Sending an SMS is an asynchronous operation by nature. When we are sending an SMS to the Telecom Provider on your behalf, they acknowledge the message then schedule it for delivery as soon as possible.
For example the mobile headset may not have service at the specific time you're sending the SMS.
So in order to receive status changes about an SMS after it has been sent, you need a way to receive events generated by our system. Enters webhooks.
#
How does it work ?
Webhooks are simply an api call that our system will make when it needs to notify you about a specific event
sequenceDiagram
autonumber
participant Your system
participant Sofy
Your system->>Sofy: POST /sms
Sofy->>Your system: "pending" status
Note left of Sofy: Reply immediately with and ID for this SMS
loop
Sofy-->Sofy: Process the message
end
alt Couldn't not process
Sofy->>Your system: "errored" status
end
Sofy->>Telecom Provider: Send SMS
Sofy->>Your system: "sent" status
loop SMS Center
Telecom Provider-->Telecom Provider: Deliver SMS to headset
end
Telecom Provider-->>Sofy: Sms status update
Sofy->>Your system: Notify via Webhook
#
Register a webhook
You can create an api endpoint on your system or use a no-code solution to receive webhooks. You need to have an api url to provide when creating a webhook resource. Once created, the webhook will receive all further status callbacks. You can unregister your webhook at a later point if your url has changed for example.
You can then create a Webhook by calling the /webhooks endpoint.
The provided url will be called using the POST http verb.
For example if your url is https://yourdomain.com/api/sofyStatus
curl -X 'POST' \
'https://api.sofy.fr/v1/webhooks' \
-H 'accept: application/json' \
-H 'X-API-KEY-ID: xxxxx' \
-H 'X-API-KEY-SECRET: yyyyy' \
-H 'Content-Type: application/json' \
-d '{
"url": "https://yourdomain.com/api/sofyStatus",
"events": ["sms.status"]
}'
import axios from 'axios';
axios.post(
'https://api.sofy.fr/v1/webhooks',
{
url: 'https://yourdomain.com/api/sofyStatus',
events: ['sms.status'],
},
{
headers: {
'X-API-KEY-ID': 'xxxxx',
'X-API-KEY-SECRET': 'yyyyy',
},
},
);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "https://api.sofy.fr/v1/webhooks");
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
"X-API-KEY-ID: " . $ID,
"X-API-KEY-SECRET: " . $SECRET,
"Content-Type: application/json"
));
$payload = json_encode(array("events" => array('sms.status'), "url" => "https://myapiurl.com/statuses"));
echo $payload;
curl_setopt($ch, CURLOPT_POSTFIELDS, $payload);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
echo $response;
#
Examples
{
"data": [
{
"body": "Hello world !",
"from": "36789",
"to": "590690112233",
"createdAt": "2022-12-29T18:24:27.000Z",
"updatedAt": "2022-12-29T18:24:44.938Z",
"id": "zzzzz",
"status": "sent",
"statusReason": "",
"price": 0.08,
"parts": 1
}
],
"webhookId": "xxxxx",
"id": "yyyyy",
"type": "sms.status"
}
{
"data": [
{
"body": "Hello world !",
"from": "36789",
"to": "590690112233",
"createdAt": "2022-12-29T18:24:27.000Z",
"updatedAt": "2022-12-29T18:24:44.938Z",
"id": "zzzzz",
"status": "delivered",
"statusReason": "DELIVRD",
"price": 0.08,
"parts": 1
}
],
"webhookId": "xxxxx",
"id": "yyyyy",
"type": "sms.status"
}
{
"data": [
{
"body": "Hello world !",
"from": "36789",
"to": "590690112233",
"createdAt": "2022-12-29T18:24:27.000Z",
"updatedAt": "2022-12-29T18:24:44.938Z",
"id": "zzzzz",
"status": "errored",
"statusReason": "EXPIRED",
"price": 0.08,
"parts": 1
}
],
"webhookId": "xxxxx",
"id": "yyyyy",
"type": "sms.status"
}
{
"data": [
{
"body": "Hello world !",
"from": "36789",
"to": "590690112233",
"createdAt": "2022-12-29T18:24:27.000Z",
"updatedAt": "2022-12-29T18:24:44.938Z",
"id": "zzzzz",
"status": "errored",
"statusReason": "insufficient_balance",
"price": 0,
"parts": 1
}
],
"webhookId": "xxxxx",
"id": "yyyyy",
"type": "sms.status"
}
{
"data": [
{
"body": "Hello world !",
"from": "36789",
"to": "590690112233",
"createdAt": "2022-12-29T18:24:27.000Z",
"updatedAt": "2022-12-29T18:24:44.938Z",
"id": "zzzzz",
"status": "errored",
"statusReason": "invalid_phone_number",
"price": 0,
"parts": 1
}
],
"webhookId": "xxxxx",
"id": "yyyyy",
"type": "sms.status"
}
Your system should respond to webhooks with a 2xx status within 4 seconds or less. A longer response time than this is considered as a timeout.
In a typical scenario, you will receive 2 webhooks.
One when your message is sent, another one to notify you about the status of the SMS: delivered, errored
#
Webhooks replay
When called, your webhook endpoint must return a 2xx status to be considered successful. Failed webhooks will be replayed following an exponential backoff if for some reason your system couldn't handle the request at a specific time.
Replays are delayed by at least the following durations:
If even after the tenth retry, your system still couldn't handle the webhook, Sofy will discard the operation.