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"
  }
}
FieldTypeDescription
successbooleantrue for 2xx responses, false for errors
dataobject | nullResponse payload (null on error)
errorobject | nullError details (null on success)
metaobjectRequest 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 timestamp
response = 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 timestamp
response, 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 timestamp
var 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 timestamp
var 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 timestamp
result = 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 timestamp

Multi-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 URL
response, 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
end

401 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.


On this page