Send or reply to SMS
History and eligible replies for SMS-enabled numbers.
POST /api/v1/sms/messagesPermission: sms:send
Required scopes
sms:send
Required fields: from=your authorized SMS-enabled DID, to=recipient, text=message (trimmed, 1–1600 characters). Phone numbers use 10–15 digits with optional leading +. Optional didId must match from. To reply, use the inbound sender as to; there is no separate reply endpoint. Sending is allowed only as a reply to an inbound SMS from that recipient to the DID, received since the current possession SMS access start. A previously sent message, another contact, a previous possession, or a failed history lookup does not authorize the send. No account permission can start a conversation. newConversation on success is false. 201 confirms submission, not handset delivery. message contains id, smscMessageId (possibly null), didId, from, to, textLength and newConversation. No idempotency key: after timeout, inspect history before retrying to avoid duplicate delivery.
While an account is under security review, reads and operations are blocked with HTTP 403 and code account_security_review, including previously issued tokens. Do not bypass the restriction or retry automatically. Access resumes after administrative release; other limits and restrictions still apply. Pending webhooks and events during the restriction are suppressed without automatic replay. Billing, due dates and expiration follow existing rules. Follow the review at https://novodid.com/seguranca/atendimento. Only the linked security ticket can be read and answered, including attachments, on the authenticated website. Other tickets and the public API remain blocked. The customer must wait for the first staff message and may send only one reply to each new staff message, including requested attachments.
Request body
{
"from": "5511999999999",
"to": "5511988888888",
"text": "Mensagem de exemplo"
}Success response (201)
{
"message": {
"id": null,
"smscMessageId": null,
"didId": 1234,
"from": "5511999999999",
"to": "5511988888888",
"textLength": 19,
"newConversation": false
}
}Error example
{
"error": {
"code": "insufficient_scope",
"message": "Token sem permissão para esta operação."
}
}curl
curl -X POST \
-H "Authorization: Bearer $NOVODID_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{"from":"5511999999999","to":"5511988888888","text":"Mensagem de exemplo"}' \
"https://novodid.com/api/v1/sms/messages"Node
const response = await fetch("https://novodid.com/api/v1/sms/messages", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.NOVODID_API_TOKEN}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
"from": "5511999999999",
"to": "5511988888888",
"text": "Mensagem de exemplo"
})
});
const payload = await response.json();
if (!response.ok) {
throw new Error(payload.error?.message || "Erro na API NovoDID");
}
console.log({ status: response.status });Python
import os
import requests
response = requests.post(
"https://novodid.com/api/v1/sms/messages",
headers={"Authorization": f"Bearer {os.environ['NOVODID_API_TOKEN']}"},
json={
"from": "5511999999999",
"to": "5511988888888",
"text": "Mensagem de exemplo"
},
timeout=30,
)
payload = response.json()
response.raise_for_status()
print({"status": response.status_code})Go
package main
import (
"fmt"
"io"
"net/http"
"os"
"strings"
)
func main() {
req, err := http.NewRequest("POST", "https://novodid.com/api/v1/sms/messages", strings.NewReader(`{"from":"5511999999999","to":"5511988888888","text":"Mensagem de exemplo"}`))
if err != nil {
panic(err)
}
req.Header.Set("Authorization", "Bearer "+os.Getenv("NOVODID_API_TOKEN"))
req.Header.Set("Content-Type", "application/json")
res, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer res.Body.Close()
_, _ = io.Copy(io.Discard, res.Body)
if res.StatusCode >= 300 {
panic(fmt.Sprintf("NovoDID API HTTP %d", res.StatusCode))
}
fmt.Println(res.StatusCode)
}Rust
use serde_json::json;
use reqwest::blocking::Client;
use std::env;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let client = Client::new();
let response = client
.post("https://novodid.com/api/v1/sms/messages")
.bearer_auth(env::var("NOVODID_API_TOKEN")?)
.json(&json!({
"from": "5511999999999",
"to": "5511988888888",
"text": "Mensagem de exemplo"
}))
.send()?;
let status = response.status();
let _payload = response.text()?;
if !status.is_success() {
return Err(format!("NovoDID API HTTP {}", status).into());
}
println!("HTTP {}", status);
Ok(())
}PHP
<?php
$ch = curl_init("https://novodid.com/api/v1/sms/messages");
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer " . getenv("NOVODID_API_TOKEN"),
"Content-Type: application/json"
],
CURLOPT_POSTFIELDS => '{"from":"5511999999999","to":"5511988888888","text":"Mensagem de exemplo"}',
]);
$response = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($response === false || $status >= 300) {
throw new RuntimeException("NovoDID API HTTP " . $status);
}
echo $status . PHP_EOL;Ruby
require "net/http"
uri = URI("https://novodid.com/api/v1/sms/messages")
request = Net::HTTP::Post.new(uri)
request["Authorization"] = "Bearer #{ENV.fetch("NOVODID_API_TOKEN")}"
request["Content-Type"] = "application/json"
request.body = %q({"from":"5511999999999","to":"5511988888888","text":"Mensagem de exemplo"})
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == "https") do |http|
http.request(request)
end
raise "NovoDID API HTTP #{response.code}" unless response.is_a?(Net::HTTPSuccess)
puts response.codeC#
using System.Net.Http.Headers;
using System.Text;
using var client = new HttpClient();
using var request = new HttpRequestMessage(HttpMethod.Post, "https://novodid.com/api/v1/sms/messages");
request.Headers.Authorization = new AuthenticationHeaderValue(
"Bearer",
Environment.GetEnvironmentVariable("NOVODID_API_TOKEN")
);
request.Content = new StringContent(
"""
{
"from": "5511999999999",
"to": "5511988888888",
"text": "Mensagem de exemplo"
}
""",
Encoding.UTF8,
"application/json"
);
using var response = await client.SendAsync(request);
var payload = await response.Content.ReadAsStringAsync();
response.EnsureSuccessStatusCode();
Console.WriteLine(response.StatusCode);
