Desenvolvedores
Enviar SMS com a Sinch Conversation API em curl, Node.js e Python
A Conversation API é assim que você envia SMS com a Sinch. Toda mensagem passa por um único endpoint, POST https://{region}.conversation.api.sinch.com/v1/projects/{project_id}/messages:send, e o mesmo endpoint abrange RCS, WhatsApp e os outros canais de envio de mensagens. A solicitação que você escreve hoje para uma mensagem de texto tem o mesmo formato que você usará ao adicionar um segundo canal mais tarde. Este post configura um aplicativo da Conversation API com o canal de SMS e envia uma mensagem de três maneiras: com curl, com o SDK do Node.js e com o SDK do Python. Escolha a opção que corresponde à sua stack. Cada um é um script curto que você pode executar no terminal.
Você precisará de
- Uma conta da Sinch (Cadastre-se). Novas contas incluem um número de teste.
- Um telefone que possa receber SMS. Contas de teste podem limitar para quais números você pode enviar, portanto, verifique o destinatário nas configurações da conta no painel.
- Você precisa de
curlejqpara a versão shell, Node.js 20 ou posterior para Node.js, ou Python 3.9 ou posterior para Python.
Configurar um aplicativo da Conversation API
A Conversation API envia mensagens de um aplicativo. O aplicativo contém os canais que você conectou, e o canal de SMS vincula o aplicativo ao plano de serviço de SMS ao qual o número pertence.
- No painel da Sinch, abra a “Conversation API” no menu à esquerda. Aceite os termos e clique em “OBTER ACESSO” se você não a usou antes.
- Vá para “Configurações”, depois “Chaves de acesso” e crie uma chave de acesso. Copie o ID da chave e o segredo da chave. O segredo é exibido apenas uma vez.
- Vá para “Conversation API”, depois “Aplicativos” e crie um aplicativo. Escolha a região que corresponde ao plano de serviço de SMS: EUA, UE ou Brasil. Copie o ID do aplicativo.
- No aplicativo, clique em “CONFIGURAR CANAL” na linha de “SMS”, escolha o plano de serviço no menu suspenso e confirme.
Veja de onde vem cada valor:
| Variável de ambiente | Onde encontrar |
|---|---|
SINCH_PROJECT_ID | Configurações, Configurações do projeto |
SINCH_KEY_ID, SINCH_KEY_SECRET | Configurações, Chaves de acesso |
SINCH_APP_ID | Conversation API, Aplicativos. O ID do aplicativo, não o ID do projeto |
SINCH_SMS_SENDER | Números, Seus números. O número atribuído ao plano de serviço, no formato E.164 |
SINCH_REGION | A região onde você criou o aplicativo: us, eu ou br |
Exporte-as no shell:
export SINCH_PROJECT_ID="YOUR_PROJECT_ID"
export SINCH_KEY_ID="YOUR_KEY_ID"
export SINCH_KEY_SECRET="YOUR_KEY_SECRET"
export SINCH_APP_ID="YOUR_APP_ID"
export SINCH_SMS_SENDER="+12025550123"
export SINCH_REGION="us"
Mantenha o segredo da chave fora do controle de versão. Na produção, carregue-o de um gerenciador de segredos.
Enviar um SMS com curl
Duas solicitações. A primeira troca a chave de acesso por um token OAuth 2.0 de https://auth.sinch.com/oauth2/token, que dura cerca de uma hora. A segunda envia a mensagem para o endpoint messages:send na região do aplicativo.
Salve isto como send-sms.sh:
#!/usr/bin/env bash
# Send one SMS with the Sinch Conversation API using curl and jq.
# Usage: bash send-sms.sh +15551234567 "Hello from Sinch"
set -euo pipefail
: "${SINCH_PROJECT_ID:?Set SINCH_PROJECT_ID}"
: "${SINCH_KEY_ID:?Set SINCH_KEY_ID}"
: "${SINCH_KEY_SECRET:?Set SINCH_KEY_SECRET}"
: "${SINCH_APP_ID:?Set SINCH_APP_ID}"
: "${SINCH_SMS_SENDER:?Set SINCH_SMS_SENDER}"
region="${SINCH_REGION:-us}"
to="${1:?Usage: send-sms.sh }"
text="${2:?Usage: send-sms.sh }"
if [[ ! "$to" =~ ^\+[1-9][0-9]{1,14}$ ]]; then
echo "Use E.164 format for the number, for example +15551234567. Got: $to" >&2
exit 1
fi
access_token=$(curl --silent --show-error --fail-with-body \
https://auth.sinch.com/oauth2/token \
--user "$SINCH_KEY_ID:$SINCH_KEY_SECRET" \
--data grant_type=client_credentials | jq -r .access_token)
body=$(jq -n \
--arg app_id "$SINCH_APP_ID" \
--arg to "$to" \
--arg text "$text" \
--arg sender "$SINCH_SMS_SENDER" \
'{
app_id: $app_id,
recipient: { identified_by: { channel_identities: [{ channel: "SMS", identity: $to }] } },
message: { text_message: { text: $text } },
channel_properties: { SMS_SENDER: $sender }
}')
curl --silent --show-error --fail-with-body \
"https://$region.conversation.api.sinch.com/v1/projects/$SINCH_PROJECT_ID/messages:send" \
--header "Authorization: Bearer $access_token" \
--header "Content-Type: application/json" \
--data "$body"
echo
Construir o corpo com jq evita que as aspas e as quebras de linha na mensagem quebrem o JSON. Execute-o com o próprio número:
bash send-sms.sh +15551234567 "Hello from the Sinch Conversation API"
{"message_id":"01M613QSW2Q112R8FYHW29E5K9","accepted_time":"2026-10-28T11:18:46.402Z"}
O corpo da solicitação tem três partes que você usará em todos os envios:
recipient.identified_by.channel_identitiesdefine quem recebe a mensagem e em qual canal. Para SMS, a identidade é o número de telefone.message.text_message.texté a mensagem. O mesmo objetomessagetransporta mídia, cartões e outros tipos em canais que têm suporte a eles.channel_properties.SMS_SENDERé o número de onde a mensagem se origina. Você pode omiti-lo se o plano de serviço tiver um originador padrão. Defina-o de qualquer forma enquanto estiver no número de teste.
Envie um SMS com Node.js
A SDK do Node.js da Sinch gerencia o token para você. Instale-o com TypeScript e tsx:
npm init -y
npm pkg set type=module
npm install @sinch/sdk-core@1.7.0
npm install --save-dev typescript@5.9 tsx @types/node@24
mkdir -p src
Salve isto como src/send-sms.ts:
import { SinchClient } from "@sinch/sdk-core";
function requireEnv(name: string): string {
const value = process.env[name];
if (!value) {
throw new Error(`Set the ${name} environment variable`);
}
return value;
}
const [to, text] = process.argv.slice(2);
if (!to || !text) {
throw new Error('Usage: npm run send -- ""');
}
if (!/^\+[1-9]\d{1,14}$/.test(to)) {
throw new Error(`Use E.164 format for the number, for example +15551234567. Got: ${to}`);
}
const sinchClient = new SinchClient({
projectId: requireEnv("SINCH_PROJECT_ID"),
keyId: requireEnv("SINCH_KEY_ID"),
keySecret: requireEnv("SINCH_KEY_SECRET"),
conversationRegion: process.env.SINCH_REGION ?? "us",
});
const response = await sinchClient.conversation.messages.sendTextMessage({
sendMessageRequestBody: {
app_id: requireEnv("SINCH_APP_ID"),
recipient: {
identified_by: {
channel_identities: [{ channel: "SMS", identity: to }],
},
},
message: { text_message: { text } },
channel_properties: { SMS_SENDER: requireEnv("SINCH_SMS_SENDER") },
},
});
console.log(`Accepted message ${response.message_id} at ${response.accepted_time?.toISOString()}`);
Adicione um script ao package.json e execute-o:
npm pkg set scripts.send="tsx src/send-sms.ts"
npm run send -- +15551234567 "Hello from the Sinch Node.js SDK"
Accepted message 01M613R541V5R0CMSY5BNP4DSA at 2026-10-28T11:18:57.921Z
O corpo da solicitação é o mesmo JSON da versão curl, com os mesmos nomes de campo em snake_case. sendTextMessage é o atalho tipado para uma mensagem de texto. conversationRegion tem us como padrão, portanto, defina-o se o aplicativo estiver em eu ou br.
Envie um SMS com Python
A SDK do Python da Sinch oferece suporte à Conversation API a partir da versão 2.0. Instale-o em um ambiente virtual:
python3 -m venv .venv
source .venv/bin/activate
pip install sinch==2.3.0
Salve isto como send_sms.py:
import os
import re
import sys
from sinch import SinchClient
from sinch.core.exceptions import SinchException
def require_env(name: str) -> str:
value = os.environ.get(name)
if not value:
sys.exit(f"Set the {name} environment variable")
return value
if len(sys.argv) != 3:
sys.exit('Usage: python send_sms.py ""')
to, text = sys.argv[1], sys.argv[2]
if not re.fullmatch(r"\+[1-9]\d{1,14}", to):
sys.exit(f"Use E.164 format for the number, for example +15551234567. Got: {to}")
sinch_client = SinchClient(
project_id=require_env("SINCH_PROJECT_ID"),
key_id=require_env("SINCH_KEY_ID"),
key_secret=require_env("SINCH_KEY_SECRET"),
conversation_region=os.environ.get("SINCH_REGION", "us"),
)
try:
response = sinch_client.conversation.messages.send_text_message(
app_id=require_env("SINCH_APP_ID"),
text=text,
recipient_identities=[{"channel": "SMS", "identity": to}],
channel_properties={"SMS_SENDER": require_env("SINCH_SMS_SENDER")},
)
except SinchException as error:
sys.exit(f"Sinch API error: {error}")
print(f"Accepted message {response.message_id} at {response.accepted_time}")
python send_sms.py +15551234567 "Hello from the Sinch Python SDK"
Accepted message 01M613R7AK2SST6VXH24HVF278 at 2026-10-28 11:19:00.179000+00:00
O SDK do Python aceita argumentos de palavra-chave em vez de um corpo de solicitação. Defina conversation_region todas as vezes: o cliente Python não tem uma região padrão para a Conversation API.
Aceito não é entregue
Uma resposta 200 com um message_id significa que a Sinch aceitou a mensagem. Saber se o telefone a recebeu vem depois, como um relatório de entrega enviado a um webhook no aplicativo. Para SMS, o relatório muda de QUEUED_ON_CHANNEL para DELIVERED ou FAILED. O número de telefone no relatório retorna sem o + inicial, portanto, normalize os números antes de corresponder os relatórios aos destinatários.
Para obter relatórios, adicione um webhook ao aplicativo com o gatilho MESSAGE_DELIVERY. No painel, abra o aplicativo e adicione-o em Webhooks. Com a API, obtenha um token e faça uma solicitação:
SINCH_ACCESS_TOKEN=$(curl --silent --show-error --fail-with-body \
https://auth.sinch.com/oauth2/token \
--user "$SINCH_KEY_ID:$SINCH_KEY_SECRET" \
--data grant_type=client_credentials | jq -r .access_token)
curl --silent --show-error --fail-with-body \
"https://$SINCH_REGION.conversation.api.sinch.com/v1/projects/$SINCH_PROJECT_ID/webhooks" \
--header "Authorization: Bearer $SINCH_ACCESS_TOKEN" \
--header "Content-Type: application/json" \
--data '{
"app_id": "YOUR_APP_ID",
"target": "https://example.com/sinch/callbacks",
"target_type": "HTTP",
"triggers": ["MESSAGE_DELIVERY", "MESSAGE_INBOUND"]
}'
MESSAGE_INBOUND também envia as respostas. Um relatório de falha inclui um reason com um código que informa o motivo. É aí que um número de remetente rejeitado ou um destinatário para o qual a conta não pode enviar aparece. A Sinch tenta novamente um webhook que não responde com um 2xx, então o manipulador precisa lidar com a possibilidade de receber o mesmo relatório duas vezes.
Por que a solicitação tem este formato
Vale a pena explicar algumas escolhas nestes scripts, pois a documentação mostra outras opções.
OAuth 2.0 em vez de Basic auth
A Conversation API também aceita o ID da chave e o segredo como Basic auth diretamente em messages:send, e o guia de introdução o utiliza para a primeira chamada. O Basic auth tem um limite de taxa severo e destina-se a testes. A solicitação de token é uma chamada extra, os SDKs fazem isso para você e é o que será executado na produção, portanto, o script curl o utiliza desde o início.
identified_by em vez de contact_id
Você pode endereçar uma mensagem para um número de telefone com identified_by, ou para um contato que a API armazenou anteriormente com contact_id. Aplicativos criados após 16 de abril de 2025 usam o modo Dispatch por padrão, que não armazena contatos, de modo que contact_id não tem para onde apontar. identified_by funciona em ambos os modos. Mude o aplicativo para o modo Conversation se quiser que os contatos e o histórico da conversa sejam armazenados.
Definir SMS_SENDER todas as vezes
Sem SMS_SENDER, a mensagem é enviada do originador padrão do plano de serviço, se houver um. O número de teste em uma nova conta precisa que ele seja definido. Um remetente que a rede rejeita não causa falha na solicitação HTTP: ele aparece depois como um relatório de entrega FAILED. Defini-lo explicitamente torna o remetente visível no código, em vez de em uma configuração no painel.
Aponte o agente de programação para a API correta
Agentes de programação aprenderam com anos de exemplos na web, e muitos deles usam a API de SMS independente e mais antiga (XMS). Essa API chegou ao fim das vendas em 15 de abril de 2026, e continua disponível apenas para integrações já criadas nela. Qualquer coisa nova deve usar a Conversation API, mesmo em uma conta que já tenha usado a API de SMS antes. Se você tem código na API de SMS, Migrar da API de SMS da Sinch para a Conversation API o mapeia campo por campo.
Se você pedir a um agente para “enviar um SMS com a Sinch” e ele escrever um código para /xms/v1/, diga a ele qual API você deseja. Uma linha no AGENTS.md ou CLAUDE.md do projeto faz isso para todas as sessões:
## Sinch
- Send SMS with the Sinch Conversation API (`/v1/projects/{project_id}/messages:send`), not the SMS API (`/xms/v1/`).
- Use `@sinch/sdk-core` (Node.js) or `sinch` (Python), with project ID, key ID, and key secret.
A Skills de agente da Sinch vão além. Elas fornecem ao agente os formatos de solicitação da Conversation API, as regras do canal de SMS e as etapas de configuração. A Os plugins da Sinch para Claude Code, Cursor e Gemini CLI agrupam essas skills com o Servidor MCP da Sinch, que também envia SMS por meio da Conversation API.
Solução de problemas
404emmessages:send. A região no URL não corresponde à região do aplicativo. Um aplicativo criado na UE só pode ser acessado emeu.conversation.api.sinch.com. Verifique a região nas configurações do aplicativo e definaSINCH_REGIONpara corresponder.
401no endpoint de token. O ID da chave ou o segredo está incorreto, ou você usou um ID de projeto onde o ID da chave deveria estar. As chaves de acesso estão em Configurações, Chaves de acesso. Se perdeu o segredo, crie uma nova chave.
400mencionando o canal. O aplicativo não tem o canal de SMS configurado ou o canal não está vinculado a um plano de serviço. Abra o aplicativo e verifique a linha de SMS.
- A API aceitou a mensagem, mas nada chegou. Verifique o relatório de entrega do
message_id. Em uma conta de teste, verifique se o destinatário é um número para o qual a conta pode enviar. Para números dos EUA, o tráfego de um código longo de 10 dígitos precisa do registro de 10DLC marca e campanha.
- O aplicativo está em uma região diferente do número. O aplicativo deve estar na mesma região do plano de serviço de SMS. Se não corresponderem, crie um novo aplicativo na região certa e configure o canal de SMS nele.
Próximas etapas
A partir daqui, a mesma solicitação envia para outros canais. Adicione RCS ou WhatsApp ao aplicativo, dê ao destinatário uma identidade para cada canal em channel_identities e defina channel_priority_order na solicitação, por exemplo ["RCS", "SMS"]. A página de conceitos-chave explica quando a Conversation API faz o fallback para o próximo canal. Se você tem código na API de SMS independente, Migrar da API de SMS da Sinch para a Conversation API abrange lotes, relatórios de entrega e mensagens de entrada.