URL: https://docs.sent.dm/llms/start/guides/sending-messages.txt Complete guide to sending SMS and WhatsApp messages with Sent # Sending Messages Complete guide to sending SMS and WhatsApp messages using the Sent API. ## Overview A **Message** in Sent represents a single communication sent to a contact through a specific channel (SMS or WhatsApp). This guide covers the core aspects of message sending. ## The Message Lifecycle ## Sending Methods ### 1. Send to Phone Number The simplest approach - send directly to any phone number: ```bash curl -X POST "https://api.sent.dm/v3/messages" \ -H "x-api-key: $SENT_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "to": ["+1234567890"], "template": { "id": "tmpl_1234567890", "parameters": { "customerName": "John Doe", "orderNumber": "#12345" } } }' ``` ```typescript import SentDm from '@sentdm/sentdm'; const client = new SentDm(); const response = await client.messages.send({ to: ['+1234567890'], template: { id: 'tmpl_1234567890', parameters: { customerName: 'John Doe', orderNumber: '#12345' } } }); console.log(`Message ID: ${response.data.recipients[0].message_id}`); ``` ```python from sent_dm import SentDm client = SentDm() response = client.messages.send( to=["+1234567890"], template={ "id": "tmpl_1234567890", "parameters": { "customerName": "John Doe", "orderNumber": "#12345" } } ) print(f"Message ID: {response.data.recipients[0].message_id}") ``` ```go import ( "context" "github.com/sentdm/sent-dm-go" "github.com/sentdm/sent-dm-go/option" ) client := sentdm.NewClient() response, err := client.Messages.Send(context.Background(), sentdm.MessageSendParams{ To: []string{"+1234567890"}, Template: sentdm.MessageSendParamsTemplate{ ID: sentdm.String("tmpl_1234567890"), Parameters: map[string]interface{}{ "customerName": "John Doe", "orderNumber": "#12345", }, }, }) ``` ```java import dm.sent.client.SentDmClient; import dm.sent.client.okhttp.SentDmOkHttpClient; import dm.sent.core.JsonValue; import dm.sent.models.messages.MessageSendParams; SentDmClient client = SentDmOkHttpClient.fromEnv(); MessageSendParams params = MessageSendParams.builder() .addTo("+1234567890") .template(MessageSendParams.Template.builder() .id("tmpl_1234567890") .parameters(MessageSendParams.Template.Parameters.builder() .putAdditionalProperty("customerName", JsonValue.from("John Doe")) .putAdditionalProperty("orderNumber", JsonValue.from("#12345")) .build()) .build()) .build(); var response = client.messages().send(params); System.out.println("Sent: " + response.data().recipients().get(0).messageId()); ``` ```csharp using Sentdm; using Sentdm.Models.Messages; using System.Collections.Generic; SentDmClient client = new(); MessageSendParams parameters = new() { To = new List { "+1234567890" }, Template = new MessageSendParamsTemplate { Id = "tmpl_1234567890", Parameters = new Dictionary { { "customerName", "John Doe" }, { "orderNumber", "#12345" } } } }; var response = await client.Messages.SendAsync(parameters); Console.WriteLine($"Sent: {response.Data.Recipients[0].MessageId}"); ``` ```php messages->send( to: ['+1234567890'], template: [ 'id' => 'tmpl_1234567890', 'parameters' => [ 'customerName' => 'John Doe', 'orderNumber' => '#12345' ] ] ); var_dump($result->data->recipients[0]->message_id); ``` ```ruby require "sentdm" sent_dm = Sentdm::Client.new result = sent_dm.messages.send( to: ["+1234567890"], template: { id: "tmpl_1234567890", parameters: { customerName: "John Doe", orderNumber: "#12345" } } ) puts result.data.recipients[0].message_id ``` ### 2. Send to Multiple Recipients Send the same message to multiple recipients in one request: ```bash curl -X POST "https://api.sent.dm/v3/messages" \ -H "x-api-key: $SENT_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "to": ["+1234567890", "+1987654321", "+1555555555"], "template": { "id": "tmpl_1234567890", "parameters": { "announcement": "Our store is now open!" } } }' ``` ```typescript const response = await client.messages.send({ to: ['+1234567890', '+1987654321', '+1555555555'], template: { id: 'tmpl_1234567890', parameters: { announcement: 'Our store is now open!' } } }); console.log(`Sent to ${response.data.recipients.length} recipients`); ``` ```python response = client.messages.send( to=["+1234567890", "+1987654321", "+1555555555"], template={ "id": "tmpl_1234567890", "parameters": { "announcement": "Our store is now open!" } } ) print(f"Sent to {len(response.data.recipients)} recipients") ``` ```go response, err := client.Messages.Send(context.Background(), sentdm.MessageSendParams{ To: []string{"+1234567890", "+1987654321", "+1555555555"}, Template: sentdm.MessageSendParamsTemplate{ ID: sentdm.String("tmpl_1234567890"), Parameters: map[string]interface{}{ "announcement": "Our store is now open!", }, }, }) fmt.Printf("Sent to %d recipients\n", len(response.Data.Recipients)) ``` ```java import dm.sent.models.messages.MessageSendParams; import dm.sent.core.JsonValue; MessageSendParams params = MessageSendParams.builder() .addTo("+1234567890") .addTo("+1987654321") .addTo("+1555555555") .template(MessageSendParams.Template.builder() .id("tmpl_1234567890") .parameters(MessageSendParams.Template.Parameters.builder() .putAdditionalProperty("announcement", JsonValue.from("Our store is now open!")) .build()) .build()) .build(); var response = client.messages().send(params); System.out.println("Sent to " + response.data().recipients().size() + " recipients"); ``` ```csharp using Sentdm.Models.Messages; MessageSendParams parameters = new() { To = new List { "+1234567890", "+1987654321", "+1555555555" }, Template = new MessageSendParamsTemplate { Id = "tmpl_1234567890", Parameters = new Dictionary { { "announcement", "Our store is now open!" } } } }; var response = await client.Messages.SendAsync(parameters); Console.WriteLine($"Sent to {response.Data.Recipients.Count} recipients"); ``` ```php $result = $client->messages->send( to: ['+1234567890', '+1987654321', '+1555555555'], template: [ 'id' => 'tmpl_1234567890', 'parameters' => [ 'announcement' => 'Our store is now open!' ] ] ); echo "Sent to " . count($result->data->recipients) . " recipients\n"; ``` ```ruby result = sent_dm.messages.send( to: ["+1234567890", "+1987654321", "+1555555555"], template: { id: "tmpl_1234567890", parameters: { announcement: "Our store is now open!" } } ) puts "Sent to #{result.data.recipients.length} recipients" ``` **Recipient Limit:** A single request can include up to **1000 recipients**. For campaigns larger than 1000, split into multiple requests. Each API call counts as one request toward the 200 req/min rate limit. ## Channel Selection Strategies ### Automatic Selection (Default) Let Sent choose the optimal channel by omitting the `channel` field: ```bash curl -X POST "https://api.sent.dm/v3/messages" \ -H "x-api-key: $SENT_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "to": ["+1234567890"], "template": { "id": "tmpl_1234567890" } }' ``` ```typescript const response = await client.messages.send({ to: ['+1234567890'], template: { id: 'tmpl_1234567890' } // No channel field - automatic selection }); ``` ```python response = client.messages.send( to=["+1234567890"], template={ "id": "tmpl_1234567890" } # No channel parameter - automatic selection ) ``` ```go response, err := client.Messages.Send(context.Background(), sentdm.MessageSendParams{ To: []string{"+1234567890"}, Template: sentdm.MessageSendParamsTemplate{ ID: sentdm.String("tmpl_1234567890"), }, // No channel field - automatic selection }) ``` ```java MessageSendParams params = MessageSendParams.builder() .addTo("+1234567890") .template(MessageSendParams.Template.builder() .id("tmpl_1234567890") .build()) // No channel - automatic selection .build(); var response = client.messages().send(params); ``` ```csharp MessageSendParams parameters = new() { To = new List { "+1234567890" }, Template = new MessageSendParamsTemplate { Id = "tmpl_1234567890" } // No channel - automatic selection }; var response = await client.Messages.SendAsync(parameters); ``` ```php $result = $client->messages->send( to: ['+1234567890'], template: [ 'id' => 'tmpl_1234567890' ] // No channel - automatic selection ); ``` ```ruby result = sent_dm.messages.send( to: ["+1234567890"], template: { id: "tmpl_1234567890" } # No channel - automatic selection ) ``` Sent considers: - Contact's available channels - Historical delivery success rates - Cost optimization - Regional preferences ### Force Specific Channel Override automatic selection by specifying the `channel` field: #### SMS Only ```bash curl -X POST "https://api.sent.dm/v3/messages" \ -H "x-api-key: $SENT_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "to": ["+1234567890"], "template": { "id": "tmpl_1234567890" }, "channel": ["sms"] }' ``` ```typescript const response = await client.messages.send({ to: ['+1234567890'], template: { id: 'tmpl_1234567890' }, channel: ['sms'] }); ``` ```python response = client.messages.send( to=["+1234567890"], template={ "id": "tmpl_1234567890" }, channel=["sms"] ) ``` ```go response, err := client.Messages.Send(context.Background(), sentdm.MessageSendParams{ To: []string{"+1234567890"}, Channel: []string{"sms"}, Template: sentdm.MessageSendParamsTemplate{ ID: sentdm.String("tmpl_1234567890"), }, }) ``` ```java MessageSendParams params = MessageSendParams.builder() .addTo("+1234567890") .addChannel("sms") .template(MessageSendParams.Template.builder() .id("tmpl_1234567890") .build()) .build(); var response = client.messages().send(params); ``` ```csharp MessageSendParams parameters = new() { To = new List { "+1234567890" }, Channels = new List { "sms" }, Template = new MessageSendParamsTemplate { Id = "tmpl_1234567890" } }; var response = await client.Messages.SendAsync(parameters); ``` ```php $result = $client->messages->send( to: ['+1234567890'], template: [ 'id' => 'tmpl_1234567890' ], channels: ['sms'] ); ``` ```ruby result = sent_dm.messages.send( to: ["+1234567890"], template: { id: "tmpl_1234567890" }, channels: ["sms"] ) ``` #### WhatsApp Only If WhatsApp is not available for this contact, the message will fail with no fallback. ```bash curl -X POST "https://api.sent.dm/v3/messages" \ -H "x-api-key: $SENT_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "to": ["+1234567890"], "template": { "id": "tmpl_1234567890" }, "channel": ["whatsapp"] }' ``` ```typescript const response = await client.messages.send({ to: ['+1234567890'], template: { id: 'tmpl_1234567890' }, channel: ['whatsapp'] }); ``` ```python response = client.messages.send( to=["+1234567890"], template={ "id": "tmpl_1234567890" }, channel=["whatsapp"] ) ``` ```go response, err := client.Messages.Send(context.Background(), sentdm.MessageSendParams{ To: []string{"+1234567890"}, Channel: []string{"whatsapp"}, Template: sentdm.MessageSendParamsTemplate{ ID: sentdm.String("tmpl_1234567890"), }, }) ``` ```java MessageSendParams params = MessageSendParams.builder() .addTo("+1234567890") .addChannel("whatsapp") .template(MessageSendParams.Template.builder() .id("tmpl_1234567890") .build()) .build(); var response = client.messages().send(params); ``` ```csharp MessageSendParams parameters = new() { To = new List { "+1234567890" }, Channels = new List { "whatsapp" }, Template = new MessageSendParamsTemplate { Id = "tmpl_1234567890" } }; var response = await client.Messages.SendAsync(parameters); ``` ```php $result = $client->messages->send( to: ['+1234567890'], template: [ 'id' => 'tmpl_1234567890' ], channels: ['whatsapp'] ); ``` ```ruby result = sent_dm.messages.send( to: ["+1234567890"], template: { id: "tmpl_1234567890" }, channels: ["whatsapp"] ) ``` #### Multiple Channels Simultaneously When you specify multiple channels, Sent creates a separate message for each (recipient, channel) pair and dispatches them all. You receive a `message_id` per channel. ```bash curl -X POST "https://api.sent.dm/v3/messages" \ -H "x-api-key: $SENT_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "to": ["+1234567890"], "template": { "id": "tmpl_1234567890" }, "channel": ["whatsapp", "sms"] }' ``` ```typescript const response = await client.messages.send({ to: ['+1234567890'], template: { id: 'tmpl_1234567890' }, channel: ['whatsapp', 'sms'] }); ``` ```python response = client.messages.send( to=["+1234567890"], template={ "id": "tmpl_1234567890" }, channel=["whatsapp", "sms"] ) ``` ```go response, err := client.Messages.Send(context.Background(), sentdm.MessageSendParams{ To: []string{"+1234567890"}, Channel: []string{"whatsapp", "sms"}, Template: sentdm.MessageSendParamsTemplate{ ID: sentdm.String("tmpl_1234567890"), }, }) ``` ```java MessageSendParams params = MessageSendParams.builder() .addTo("+1234567890") .addChannel("whatsapp") .addChannel("sms") .template(MessageSendParams.Template.builder() .id("tmpl_1234567890") .build()) .build(); var response = client.messages().send(params); ``` ```csharp MessageSendParams parameters = new() { To = new List { "+1234567890" }, Channels = new List { "whatsapp", "sms" }, Template = new MessageSendParamsTemplate { Id = "tmpl_1234567890" } }; var response = await client.Messages.SendAsync(parameters); ``` ```php $result = $client->messages->send( to: ['+1234567890'], template: [ 'id' => 'tmpl_1234567890' ], channels: ['whatsapp', 'sms'] ); ``` ```ruby result = sent_dm.messages.send( to: ["+1234567890"], template: { id: "tmpl_1234567890" }, channels: ["whatsapp", "sms"] ) ``` ## Response Overview ### Success Response (202 Accepted) ```json { "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" } } ``` **Important:** Store the `message_id` from each recipient object — you'll need it to track delivery status. ### Error Response (4xx/5xx) ```json { "success": false, "data": null, "error": { "code": "BUSINESS_003", "message": "Account balance is insufficient to send this message", "details": null, "doc_url": "https://docs.sent.dm/errors/BUSINESS_003" }, "meta": { "request_id": "req_7X9zKp2jDw", "timestamp": "2026-03-04T11:28:25.2096416+00:00", "version": "v3" } } ``` Common error codes: - `RESOURCE_002` - Template not found or not approved - `BUSINESS_003` - Insufficient account balance - `BUSINESS_002` - Rate limit exceeded (200 req/min standard, 10 req/min sensitive) - `VALIDATION_002` - Invalid phone number format - `BUSINESS_005` - Template not approved for sending - `BUSINESS_007` - Channel not available for this contact - `BUSINESS_008` - Operation would exceed quota ## Next Steps ---