Message Response Handling
This page is a lookup for the responses POST /v3/messages returns: the success/data/error envelope, per-recipient message IDs, and the error payloads for validation, authentication, and rate-limit failures. For production retry patterns, refer to Error Handling. For inbound messages and RCS suggestion-chip taps, refer to Two-Way Conversations.
Response Structure
All API responses follow a consistent structure:
{
"success": boolean,
"data": object | null,
"error": object | null,
"meta": {
"request_id": string,
"timestamp": string,
"version": "v3"
}
}| Field | Type | Description |
|---|---|---|
success | boolean | true for 2xx responses, false for errors |
data | object | null | Response payload (null on error) |
error | object | null | Error details (null on success) |
meta | object | Request metadata including request_id for support |
Success Response (202 Accepted)
When a message is successfully accepted:
{
"success": true,
"data": {
"status": "QUEUED",
"template_id": "7ba7b820-9dad-11d1-80b4-00c04fd430c8",
"template_name": "order_confirmation",
"recipients": [
{
"message_id": "8ba7b830-9dad-11d1-80b4-00c04fd430c8",
"to": "+14155551234",
"channel": "sms"
}
]
},
"error": null,
"meta": {
"request_id": "req_7X9zKp2jDw",
"timestamp": "2026-03-04T11:28:25.2096416+00:00",
"version": "v3"
}
}const response = await client.messages.send({
to: ['+1234567890'],
template: { id: 'tmpl_123' }
});
// Access response data
console.log(response.data.status); // "QUEUED"
console.log(response.data.template_id); // Template UUID
console.log(response.data.template_name);
// Access recipient info
const recipient = response.data.recipients[0];
console.log(recipient.message_id); // Message UUID for tracking
console.log(recipient.to); // Phone number
console.log(recipient.channel); // "sms", "whatsapp", or "rcs"
// Access metadata
console.log(response.meta.request_id); // For support inquiries
console.log(response.meta.timestamp); // Response timestampresponse = client.messages.send(
to=["+1234567890"],
template={"id": "tmpl_123"}
)
# Access response data
print(response.data.status) # "QUEUED"
print(response.data.template_id) # Template UUID
print(response.data.template_name)
# Access recipient info
recipient = response.data.recipients[0]
print(recipient.message_id) # Message UUID for tracking
print(recipient.to) # Phone number
print(recipient.channel) # "sms", "whatsapp", or "rcs"
# Access metadata
print(response.meta.request_id) # For support inquiries
print(response.meta.timestamp) # Response timestampresponse, err := client.Messages.Send(context.Background(), params)
if err != nil {
log.Fatal(err)
}
// Access response data
fmt.Println(response.Data.Status) // "QUEUED"
fmt.Println(response.Data.TemplateID) // Template UUID
fmt.Println(response.Data.TemplateName)
// Access recipient info
recipient := response.Data.Recipients[0]
fmt.Println(recipient.MessageID) // Message UUID for tracking
fmt.Println(recipient.To) // Phone number
fmt.Println(recipient.Channel) // "sms", "whatsapp", or "rcs"
// Access metadata
fmt.Println(response.Meta.RequestID) // For support inquiries
fmt.Println(response.Meta.Timestamp) // Response timestampvar response = client.messages().send(params);
// Access response data
System.out.println(response.data().status()); // "QUEUED"
System.out.println(response.data().templateId()); // Template UUID
System.out.println(response.data().templateName());
// Access recipient info
var recipient = response.data().recipients().get(0);
System.out.println(recipient.messageId()); // Message UUID for tracking
System.out.println(recipient.to()); // Phone number
System.out.println(recipient.channel()); // "sms", "whatsapp", or "rcs"
// Access metadata
System.out.println(response.meta().requestId()); // For support inquiries
System.out.println(response.meta().timestamp()); // Response timestampvar response = await client.Messages.Send(parameters);
// Access response data
Console.WriteLine(response.Data.Status); // "QUEUED"
Console.WriteLine(response.Data.TemplateId); // Template UUID
Console.WriteLine(response.Data.TemplateName);
// Access recipient info
var recipient = response.Data.Recipients[0];
Console.WriteLine(recipient.MessageId); // Message UUID for tracking
Console.WriteLine(recipient.To); // Phone number
Console.WriteLine(recipient.Channel); // "sms", "whatsapp", or "rcs"
// Access metadata
Console.WriteLine(response.Meta.RequestId); // For support inquiries
Console.WriteLine(response.Meta.Timestamp); // Response timestamp$result = $client->messages->send(
to: ['+1234567890'],
template: ['id' => 'tmpl_123']
);
// Access response data
echo $result->data->status; // "QUEUED"
echo $result->data->template_id; // Template UUID
echo $result->data->template_name;
// Access recipient info
$recipient = $result->data->recipients[0];
echo $recipient->message_id; // Message UUID for tracking
echo $recipient->to; // Phone number
echo $recipient->channel; // "sms", "whatsapp", or "rcs"
// Access metadata
echo $result->meta->request_id; // For support inquiries
echo $result->meta->timestamp; // Response timestampresult = sent_dm.messages.send(
to: ["+1234567890"],
template: { id: "tmpl_123" }
)
# Access response data
puts result.data.status # "QUEUED"
puts result.data.template_id # Template UUID
puts result.data.template_name
# Access recipient info
recipient = result.data.recipients[0]
puts recipient.message_id # Message UUID for tracking
puts recipient.to # Phone number
puts recipient.channel # "sms", "whatsapp", or "rcs"
# Access metadata
puts result.meta.request_id # For support inquiries
puts result.meta.timestamp # Response timestampMulti-Channel Response
When sending to multiple channels, you get one recipient entry per (recipient, channel) pair:
{
"success": true,
"data": {
"status": "QUEUED",
"template_id": "7ba7b820-9dad-11d1-80b4-00c04fd430c8",
"template_name": "order_confirmation",
"recipients": [
{
"message_id": "msg-uuid-1",
"to": "+14155551234",
"channel": "whatsapp"
},
{
"message_id": "msg-uuid-2",
"to": "+14155551234",
"channel": "sms"
}
]
},
"error": null,
"meta": {
"request_id": "req_7X9zKp2jDw",
"timestamp": "2026-03-04T11:28:25.2096416+00:00",
"version": "v3"
}
}Error Responses
400 Bad Request (Validation Error)
{
"success": false,
"data": null,
"error": {
"code": "VALIDATION_004",
"message": "Request validation failed",
"details": {
"to": ["'to' must contain at least one recipient"],
"template": ["'template' is required"]
},
"doc_url": "https://docs.sent.dm/errors/VALIDATION_004"
},
"meta": {
"request_id": "req_7X9zKp2jDw",
"timestamp": "2026-03-04T11:28:25.2096416+00:00",
"version": "v3"
}
}import { ValidationError } from '@sentdm/sentdm';
try {
const response = await client.messages.send({
to: [], // Empty array - will fail validation
template: { id: 'tmpl_123' }
});
} catch (error) {
if (error instanceof ValidationError) {
console.log(error.code); // "VALIDATION_004"
console.log(error.message); // "Request validation failed"
console.log(error.details); // { to: [...], template: [...] }
console.log(error.docUrl); // Documentation URL
}
}from sent_dm.errors import ValidationError
try:
response = client.messages.send(
to=[], # Empty list - will fail validation
template={"id": "tmpl_123"}
)
except ValidationError as e:
print(e.code) # "VALIDATION_004"
print(e.message) # "Request validation failed"
print(e.details) # {"to": [...], "template": [...]}
print(e.doc_url) # Documentation URLresponse, err := client.Messages.Send(context.Background(), params)
if err != nil {
if validationErr, ok := err.(*sentdm.ValidationError); ok {
fmt.Println(validationErr.Code) // "VALIDATION_004"
fmt.Println(validationErr.Message) // "Request validation failed"
fmt.Println(validationErr.Details) // Field-specific errors
fmt.Println(validationErr.DocURL) // Documentation URL
}
}try {
var response = client.messages().send(params);
} catch (ValidationException e) {
System.out.println(e.getCode()); // "VALIDATION_004"
System.out.println(e.getMessage()); // "Request validation failed"
System.out.println(e.getDetails()); // Field-specific errors
System.out.println(e.getDocUrl()); // Documentation URL
}try
{
var response = await client.Messages.Send(parameters);
}
catch (ValidationException ex)
{
Console.WriteLine(ex.Code); // "VALIDATION_004"
Console.WriteLine(ex.Message); // "Request validation failed"
Console.WriteLine(ex.Details); // Field-specific errors
Console.WriteLine(ex.DocUrl); // Documentation URL
}use SentDM\Exceptions\ValidationException;
try {
$result = $client->messages->send(to: [], template: ['id' => 'tmpl_123']);
} catch (ValidationException $e) {
echo $e->getCode(); // "VALIDATION_004"
echo $e->getMessage(); // "Request validation failed"
print_r($e->getDetails()); // Field-specific errors
echo $e->getDocUrl(); // Documentation URL
}begin
result = sent_dm.messages.send(to: [], template: { id: "tmpl_123" })
rescue Sentdm::ValidationError => e
puts e.code # "VALIDATION_004"
puts e.message # "Request validation failed"
puts e.details # Field-specific errors
puts e.doc_url # Documentation URL
end401 Unauthorized
Invalid or missing API key:
{
"success": false,
"data": null,
"error": {
"code": "AUTH_001",
"message": "Invalid API key",
"details": null,
"doc_url": "https://docs.sent.dm/errors/AUTH_001"
}
}404 Not Found
Template not found:
{
"success": false,
"data": null,
"error": {
"code": "RESOURCE_002",
"message": "Template not found",
"details": null,
"doc_url": "https://docs.sent.dm/errors/RESOURCE_002"
}
}429 Rate Limit
Too many requests:
{
"success": false,
"data": null,
"error": {
"code": "BUSINESS_002",
"message": "Rate limit exceeded. Retry after 60 seconds",
"details": {
"retry_after": 60,
"limit": 200,
"window": "60s"
},
"doc_url": "https://docs.sent.dm/errors/BUSINESS_002"
}
}Insufficient Balance (Asynchronous)
POST /v3/messages does not return a synchronous payment error. Sends are accepted with 202 even when your balance is too low; each affected message is then finalized as BLOCKED and fires a message.blocked webhook event. Refer to Queue for Later in the Error Handling guide for the recovery pattern, and to BUSINESS_003 in the Error Catalog for the legacy v2 behavior.
Error Code Reference
The preceding examples show the response shapes your handler parses. For the complete enumeration of error codes with causes and remediation steps, refer to the Error Catalog.
Handling Errors in Production
The Error Handling guide owns production error handling: classifying retryable failures, exponential backoff with jitter, circuit breakers, and channel fallbacks. For safe re-sends with idempotency keys, refer to How to retry Sent API requests safely.
Related Guides
Sending Messages
Core message sending guide with all SDK examples
Best Practices
Message ID storage, idempotency, and cost optimization
Error Handling
Comprehensive error handling patterns
Two-Way Conversations
Inbound messages, opt-out keywords, and RCS suggestion chips
Message Best Practices
Harden your Sent send path for production: store per-recipient message IDs, make critical sends idempotent, apply RCS send rules, and estimate bulk costs.
SMS Length, Segments & Cost
How Sent counts SMS segments, how segments map to billing, and practical tips to keep messages short and predictable