API do Inova SMS
Envie SMS pelos chips conectados à sua conta, gere códigos de verificação e receba respostas. Todas as chamadas usam JSON e o endereço base é .
Base: /api/v1
Autenticação
Crie uma chave no painel em Integração > API e OTP. Ela aparece uma única vez. Envie em todo pedido, de uma destas formas:
Authorization: Bearer isk_XXXXXXXXXXXXXXXX
X-API-Key: isk_XXXXXXXXXXXXXXXX
Limite padrão: 120 requisições por minuto por chave (resposta 429 com Retry-After).
Fila e ritmo de envio
A API não envia na hora: ela coloca na fila, e cada aparelho busca as mensagens no ritmo seguro do chip (limite por dia, por hora, intervalo e janela de horário configurados no painel). Códigos OTP passam na frente e podem sair fora da janela. Por isso o status começa como fila e muda para enviada, entregue ou falhou. Use os webhooks para saber na hora.
| Status | Significado |
|---|---|
fila | Aguardando um chip livre ou o horário agendado |
enviando | O aparelho pegou e está enviando |
enviada | Saiu do chip |
entregue | A operadora confirmou a entrega (nem toda operadora envia esse aviso) |
falhou | Erro no envio. Veja o campo erro |
cancelada / expirada | Cancelada, número descadastrado ou validade vencida antes de sair |
Enviar SMS
/api/v1/sms| Campo | Tipo | Descrição |
|---|---|---|
para | texto ou lista | Número com DDD, em qualquer formato: (88) 99999-0000, 88999990000, +5588999990000. Lista de até 100. |
mensagem | texto | O texto. Até 6 partes de SMS. |
referencia | texto, opcional | Seu identificador (até 80). Repetir a mesma referência não duplica o envio: devolve a mensagem já criada. |
agendar_para | data, opcional | 2026-11-12 08:00. Sai a partir desse horário, respeitando a janela do chip. |
validade_min | número, opcional | Se não sair em X minutos, expira em vez de chegar atrasada. |
dispositivo_id | número, opcional | Força um aparelho. Sem ele, qualquer chip livre (rodízio). |
remover_acentos | sim/não, opcional | Padrão da conta (ligado). Sem acento cabe 160 caracteres por SMS; com acento, 70. |
curl -X POST /api/v1/sms \
-H "Authorization: Bearer SUA_CHAVE" -H "Content-Type: application/json" \
-d '{"para":"(88) 99999-0000","mensagem":"Ola Ana, consulta amanha 14h. Responda 1 para confirmar.","referencia":"agenda-1234"}'
HTTP 201
{"mensagens":[{"id":5821,"para":"+5588999990000","status":"fila","segmentos":1,"codificacao":"gsm","referencia":"agenda-1234", ...}],
"aceitas":1,"recusadas":[]}
Com lista em para, números inválidos ou descadastrados vão em recusadas e os outros seguem.
Consultar uma mensagem
/api/v1/sms/{id}{"mensagem":{"id":5821,"status":"entregue","enviado_em":"2026-11-10 14:02:11","entregue_em":"2026-11-10 14:02:19","erro":null, ...}}
Listar mensagens
/api/v1/sms?status=&desde_id=&referencia=&limite=50Mais recentes primeiro, até 200 por chamada. Use desde_id para buscar só as novas.
Cancelar
/api/v1/sms/{id}Só funciona enquanto a mensagem está na fila. Depois disso devolve 409.
Respostas recebidas
/api/v1/recebidas?desde_id=&limite=50{"recebidas":[{"id":77,"de":"+5588999990000","mensagem":"1","recebido_em":"2026-11-10 14:05:40","em_resposta_a":5821}]}
Respostas que são só SAIR, PARAR, CANCELAR, STOP (e outras configuradas) descadastram o número automaticamente.
Código de verificação: enviar
/api/v1/otp/enviar| Campo | Descrição |
|---|---|
para | Número da pessoa |
tamanho | 4 a 8 dígitos (padrão 6) |
validade_min | 1 a 30 minutos (padrão 10) |
mensagem | Opcional, precisa ter {codigo}. Pode usar {minutos}. |
{"otp_id":42,"para":"+5588999990000","expira_em":"2026-11-10 14:12:00","mensagem_id":5822}
Máximo de 3 códigos por número a cada 10 minutos. Um código novo invalida o anterior. O código nunca volta na resposta: só a pessoa vê.
Código de verificação: conferir
/api/v1/otp/verificar{"otp_id":42,"codigo":"482913"} ou {"para":"88999990000","codigo":"482913"}
{"valido":true,"para":"+5588999990000"}
{"valido":false,"motivo":"codigo_incorreto","tentativas_restantes":3}
Motivos: codigo_incorreto, expirado, ja_usado, tentativas_esgotadas (5 tentativas), nao_encontrado.
Aparelhos
/api/v1/dispositivos{"dispositivos":[{"id":3,"nome":"Moto G recepção","online":true,"bateria":100,"carregando":1,"pausado":false}]}
Conta
/api/v1/conta{"conta":{"id":12,"nome":"Clínica Vida","situacao":"ativa","vencimento":"2026-12-05","hoje":{"enviadas":130,"na_fila":12}}}
Webhooks
Cadastre a URL do seu sistema no painel em Integração > Webhooks e escolha os eventos. Cada evento chega como POST JSON:
{"evento":"sms.recebida","enviado_em":"2026-11-10T14:05:41-03:00",
"dados":{"id":77,"de":"+5588999990000","mensagem":"1","em_resposta_a":5821,"referencia_original":"agenda-1234","descadastrou":false}}
| Evento | Quando |
|---|---|
sms.enviada | Saiu do chip |
sms.entregue | Operadora confirmou |
sms.falhou | Falha no envio, com erro |
sms.recebida | Chegou SMS no chip (resposta) |
linha.pausada | Chip pausado após 5 falhas seguidas |
dispositivo.offline | Aparelho 10 min sem conexão com mensagens na fila |
Conferir a assinatura
Cabeçalhos: X-Inova-Evento, X-Inova-Timestamp e X-Inova-Assinatura = sha256= + HMAC-SHA256 de timestamp + "." + corpo com o segredo do webhook.
<?php
$corpo = file_get_contents('php://input');
$ts = $_SERVER['HTTP_X_INOVA_TIMESTAMP'];
$certo = 'sha256=' . hash_hmac('sha256', $ts . '.' . $corpo, 'SEU_SEGREDO');
if (!hash_equals($certo, $_SERVER['HTTP_X_INOVA_ASSINATURA']) || abs(time() - (int)$ts) > 300) {
http_response_code(401); exit;
}
echo 'ok'; // qualquer 2xx confirma
Sem resposta 2xx, tentamos de novo em 1, 5, 15 e 60 minutos, 3 horas e 12 horas.
Erros
| HTTP | Quando |
|---|---|
| 401 | Chave ausente, inválida ou revogada |
| 402 | Conta bloqueada por pendência |
| 403 | Plano sem acesso à API |
| 404 | Mensagem ou aparelho não encontrado nesta conta |
| 409 | Número descadastrado ("optout": true) ou mensagem que não dá mais para cancelar |
| 422 | Campo inválido. O corpo traz erro e campo |
| 429 | Limite de requisições ou de códigos OTP |
{"erro":"Número de telefone inválido: 1234","campo":"para"}