Skip to main content
When LaraCopilot sends an SMS it registers a callback URL with the gateway. Once the carrier confirms delivery (or failure), the gateway POSTs a delivery receipt — commonly called a DLR — back to that URL. LaraCopilot handles the incoming DLR, looks up the corresponding SmsMessage record by its external message ID, and updates both delivery_status and delivered_at. No further action is required on your side: the status is immediately visible on the message record.

DLR webhook endpoint

LaraCopilot exposes two equivalent URLs that accept inbound DLR callbacks. Both resolve to the same handler logic. The {smsGateway} path segment is the integer ID of the gateway record in LaraCopilot. You typically configure this URL directly in your gateway or include it as the callback_url when calling POST /api/sms-gateways//send.
Path parameters
integer
required
The ID of the SMS gateway that is delivering the receipt.
Payload fields accepted LaraCopilot accepts the DLR payload as either JSON or form-encoded data. It reads the following fields:
string
The external message identifier returned by the gateway when the SMS was submitted. Also accepted as id or messageId — LaraCopilot checks all three in that order.
string
Delivery status string from the gateway. Also accepted as message_status. When neither field is present, LaraCopilot defaults the status to "delivered".
What happens LaraCopilot queries SmsMessage records for a row matching both sms_gateway_id and external_message_id. If a match is found it performs the following updates on that record:
  • delivery_status — set to the lowercased value of status or message_status from the payload (default: "delivered").
  • delivered_at — set to the current timestamp.
  • remote_response — the inbound DLR payload is merged into the existing remote_response object so the full gateway conversation is preserved.
If no matching record is found, LaraCopilot returns 200 OK with {"message": "DLR received"} and takes no further action. Response
The endpoint always returns HTTP 200. Gateway retry logic based on non-2xx responses will not be triggered.

Configuring the callback URL

When you call POST /api/sms-gateways//send, include callback_url in the request body to tell LaraCopilot where the gateway should send the DLR.
Send with explicit callback URL
When callback_url is omitted, LaraCopilot automatically sets it to:
This default means the DLR will always be routed back correctly as long as your LaraCopilot instance is publicly reachable by the gateway.

Message status values

delivery_status on an SmsMessage record moves through the following states:
The status value sent in the DLR payload is lowercased and written directly to delivery_status. If your gateway sends values such as "DELIVRD" or "UNDELIV", those exact lowercased strings will appear on the record.

Example DLR payload

The following is a representative payload that a Jasmin-compatible gateway sends to the callback URL. Your gateway documentation should confirm the exact fields it uses.
Example DLR payload from gateway
LaraCopilot extracts message_id and status from this payload. All other fields are merged into remote_response on the matching SmsMessage record for your records.

Full SMS lifecycle

1

Send request

Your application calls POST /api/sms-gateways/{id}/send. LaraCopilot creates an SmsMessage with delivery_status: "queued".
2

Gateway dispatch

LaraCopilot forwards the message to the gateway over HTTP(S) with Basic Auth. The callback_url (your DLR endpoint) is included in the payload as dlr-url.
3

Submitted

On a successful gateway response, delivery_status is updated to "submitted" and submitted_at is recorded. The send API returns the message object at this point.
4

DLR callback

The gateway POSTs a delivery receipt to your callback_url. LaraCopilot matches the message_id, updates delivery_status to "delivered" (or "failed"), and sets delivered_at.

Security: validating callback_token

Without token validation, any party that knows your DLR URL can forge delivery receipts and manipulate message status records.
Each gateway record has a callback_token field. When configuring your gateway in LaraCopilot, set a long random string as the token and configure your gateway to include it in every DLR request — typically as a query parameter or custom header. Your gateway configuration or a reverse-proxy rule should reject DLR requests that do not carry the expected token before they reach LaraCopilot. The callback_token value is available on the gateway object returned by GET /api/sms-gateways/.
Retrieve a gateway's callback_token