Uma plataforma SUDOMAKE

Documentação da Kassala API — SMS e Email

Envia SMS, códigos OTP e Email para os teus clientes em Angola, e consulta o saldo da tua conta em tempo real, com uma API RESTful simples baseada em JSON.

Base URL https://smsapi.sudomakes.com/api
Formato application/json
Moeda AOA (Kwanza)

Introdução

A Kassala, uma plataforma SUDOMAKE, permite integrar envio de SMS, códigos OTP e Email para números e endereços angolanos em qualquer aplicação ou website. Regista-te em smsapi.sudomakes.com, cria uma chave de API em "Chaves" no Dashboard e começa a enviar pedidos.

Autenticação

Cada pedido precisa de um campo api_key — a versão encriptada de uma das tuas chaves, copiável a partir de "Chaves" no Dashboard. Podes ter várias chaves ao mesmo tempo (uma por aplicação, por exemplo) e revogar qualquer uma delas a qualquer momento sem afectar as restantes.

Ao criar uma chave escolhes se ela fica limitada por domínio ou sem restrição:

  • Limitada por domínio — pensada para chaves usadas directamente no browser (JavaScript numa página web, que envia sempre um cabeçalho Origin/Referer): só aceita pedidos vindos de um dos domínios que registares para essa chave. Podes adicionar, remover ou trocar esses domínios a qualquer momento em "Chaves" no Dashboard.
  • Sem restrição — pensada para apps móveis ou para chamadas feitas a partir do teu próprio servidor (PHP, Node.js, Python, curl, Postman, etc.), que não têm um domínio de página associado. Este tipo de pedido nunca envia Origin/Referer, por isso é sempre autorizado pela api_key sozinha, independentemente de a chave estar ou não marcada como "limitada por domínio".
Revogar uma chave é definitivo e imediato — qualquer aplicação que ainda a use passa a receber erro de autorização. Se precisares de continuar a usar o acesso, cria uma chave nova antes de revogar a antiga.

Exemplo servidor-a-servidor (PHP)

$ch = curl_init('https://smsapi.sudomakes.com/api/saldo');
curl_setopt_array($ch, [
    CURLOPT_POST => true,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
    CURLOPT_POSTFIELDS => json_encode([
        'api_key' => $apiKey,
    ]),
]);
$resposta = json_decode(curl_exec($ch), true);

Endpoints

Todos os endpoints abaixo aceitam pedidos POST com corpo em JSON ou multipart/form-data e respondem em JSON.

POST /api/enviar-sms

Envia uma mensagem SMS para um número angolano.

Parâmetros

Campo Tipo Descrição
api_key string obrigatório A tua chave de API encriptada.
destinatario string obrigatório Número angolano de destino (ex: 923000000 ou +244923000000).
mensagem string obrigatório Conteúdo da mensagem a enviar.

Exemplo de pedido

curl -X POST "https://smsapi.sudomakes.com/api/enviar-sms" \
  -H "Content-Type: application/json" \
  -d '{
    "api_key": "a_tua_chave_encriptada",
    "destinatario": "923000000",
    "mensagem": "Olá! A tua encomenda foi enviada."
  }'
fetch("https://smsapi.sudomakes.com/api/enviar-sms", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    api_key: "a_tua_chave_encriptada",
    destinatario: "923000000",
    mensagem: "Olá! A tua encomenda foi enviada."
  })
})
  .then((res) => res.json())
  .then((dados) => console.log(dados));
$.ajax({
  url: "https://smsapi.sudomakes.com/api/enviar-sms",
  method: "POST",
  contentType: "application/json",
  data: JSON.stringify({
    api_key: "a_tua_chave_encriptada",
    destinatario: "923000000",
    mensagem: "Olá! A tua encomenda foi enviada."
  }),
  success: function (resposta) {
    console.log(resposta);
  }
});
const resposta = await fetch("https://smsapi.sudomakes.com/api/enviar-sms", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    api_key: "a_tua_chave_encriptada",
    destinatario: "923000000",
    mensagem: "Olá! A tua encomenda foi enviada."
  })
});
const dados = await resposta.json();
console.log(dados);
$ch = curl_init('https://smsapi.sudomakes.com/api/enviar-sms');
curl_setopt_array($ch, [
    CURLOPT_POST => true,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
    CURLOPT_POSTFIELDS => json_encode([
        'api_key' => 'a_tua_chave_encriptada',
        'destinatario' => '923000000',
        'mensagem' => 'Olá! A tua encomenda foi enviada.',
    ]),
]);
$resposta = json_decode(curl_exec($ch), true);
import requests

resposta = requests.post(
    "https://smsapi.sudomakes.com/api/enviar-sms",
    json={
        "api_key": "a_tua_chave_encriptada",
        "destinatario": "923000000",
        "mensagem": "Olá! A tua encomenda foi enviada.",
    },
)
print(resposta.json())
var body = """
    {
      "api_key": "a_tua_chave_encriptada",
      "destinatario": "923000000",
      "mensagem": "Olá! A tua encomenda foi enviada."
    }""";

HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://smsapi.sudomakes.com/api/enviar-sms"))
    .header("Content-Type", "application/json")
    .POST(HttpRequest.BodyPublishers.ofString(body))
    .build();

HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());

Resposta de sucesso

{
  "status": 1,
  "otp": "SMS enviado com sucesso."
}

Resposta de erro (ex: sem saldo)

{
  "status": -1,
  "otp": "Sem créditos de SMS disponíveis. Este envio custa 35 Kz (1 segmento a 35 Kz cada) e o teu saldo actual é 12 Kz. Recarrega a conta em https://smsapi.sudomakes.com/vendas/create ou reduz o tamanho da mensagem para consumir menos segmentos."
}
Em qualquer erro nesta API, o campo com a mensagem (otp, log ou erro, conforme o endpoint) já vem com o motivo específico da falha e o que fazer para resolvê-la — não é preciso adivinhar a partir de um código de estado.
POST /api/enviar-otp

Envia um código de verificação (OTP) por SMS. Se não enviares mensagem, a API gera e envia automaticamente um código.

Parâmetros

Campo Tipo Descrição
api_key string obrigatório A tua chave de API encriptada.
destinatario string obrigatório Número angolano de destino.
mensagem string opcional Mensagem personalizada. Deixa vazio para a API gerar o código OTP automaticamente.

Exemplo de pedido

curl -X POST "https://smsapi.sudomakes.com/api/enviar-otp" \
  -H "Content-Type: application/json" \
  -d '{
    "api_key": "a_tua_chave_encriptada",
    "destinatario": "923000000"
  }'
fetch("https://smsapi.sudomakes.com/api/enviar-otp", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    api_key: "a_tua_chave_encriptada",
    destinatario: "923000000"
  })
})
  .then((res) => res.json())
  .then((dados) => console.log(dados));
$.ajax({
  url: "https://smsapi.sudomakes.com/api/enviar-otp",
  method: "POST",
  contentType: "application/json",
  data: JSON.stringify({
    api_key: "a_tua_chave_encriptada",
    destinatario: "923000000"
  }),
  success: function (resposta) {
    console.log(resposta);
  }
});
const resposta = await fetch("https://smsapi.sudomakes.com/api/enviar-otp", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    api_key: "a_tua_chave_encriptada",
    destinatario: "923000000"
  })
});
const dados = await resposta.json();
console.log(dados);
$ch = curl_init('https://smsapi.sudomakes.com/api/enviar-otp');
curl_setopt_array($ch, [
    CURLOPT_POST => true,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
    CURLOPT_POSTFIELDS => json_encode([
        'api_key' => 'a_tua_chave_encriptada',
        'destinatario' => '923000000',
    ]),
]);
$resposta = json_decode(curl_exec($ch), true);
import requests

resposta = requests.post(
    "https://smsapi.sudomakes.com/api/enviar-otp",
    json={
        "api_key": "a_tua_chave_encriptada",
        "destinatario": "923000000",
    },
)
print(resposta.json())
var body = """
    {
      "api_key": "a_tua_chave_encriptada",
      "destinatario": "923000000"
    }""";

HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://smsapi.sudomakes.com/api/enviar-otp"))
    .header("Content-Type", "application/json")
    .POST(HttpRequest.BodyPublishers.ofString(body))
    .build();

HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());

Resposta de sucesso

{
  "status": 1,
  "otp": "123456"
}

Resposta de erro (ex: número inválido)

{
  "status": -1,
  "log": "O número de telefone não é angolano. Este endpoint só entrega a números angolanos — envia o destinatario no formato 9XXXXXXXX (9 dígitos a começar por 9) ou +244 seguido desse número."
}
POST /api/saldo

Consulta o saldo actual da tua conta, em Kwanzas (AOA). Útil para mostrares o saldo no teu próprio painel ou para avisares os teus utilizadores antes que o saldo se esgote.

Parâmetros

Campo Tipo Descrição
api_key string obrigatório A tua chave de API encriptada.

Exemplo de pedido

curl -X POST "https://smsapi.sudomakes.com/api/saldo" \
  -H "Content-Type: application/json" \
  -d '{
    "api_key": "a_tua_chave_encriptada"
  }'
fetch("https://smsapi.sudomakes.com/api/saldo", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    api_key: "a_tua_chave_encriptada"
  })
})
  .then((res) => res.json())
  .then((dados) => console.log(dados));
$.ajax({
  url: "https://smsapi.sudomakes.com/api/saldo",
  method: "POST",
  contentType: "application/json",
  data: JSON.stringify({
    api_key: "a_tua_chave_encriptada"
  }),
  success: function (resposta) {
    console.log(resposta);
  }
});
const resposta = await fetch("https://smsapi.sudomakes.com/api/saldo", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    api_key: "a_tua_chave_encriptada"
  })
});
const dados = await resposta.json();
console.log(dados);
$ch = curl_init('https://smsapi.sudomakes.com/api/saldo');
curl_setopt_array($ch, [
    CURLOPT_POST => true,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
    CURLOPT_POSTFIELDS => json_encode([
        'api_key' => 'a_tua_chave_encriptada',
    ]),
]);
$resposta = json_decode(curl_exec($ch), true);
import requests

resposta = requests.post(
    "https://smsapi.sudomakes.com/api/saldo",
    json={"api_key": "a_tua_chave_encriptada"},
)
print(resposta.json())
var body = """
    {
      "api_key": "a_tua_chave_encriptada"
    }""";

HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://smsapi.sudomakes.com/api/saldo"))
    .header("Content-Type", "application/json")
    .POST(HttpRequest.BodyPublishers.ofString(body))
    .build();

HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());

Resposta de sucesso

{
  "status": true,
  "saldo": 1250.5,
  "moeda": "AOA"
}
POST /api/enviar-email

Envia um email a partir da tua própria conta SMTP. Custa 0,5 Kz por email sem anexos, mais 1 Kz por anexo. Este endpoint recebe multipart/form-data (não JSON), por causa dos anexos.

Se não indicares smtp_host/smtp_port, a API detecta automaticamente as definições certas para Gmail, Outlook/Hotmail, Yahoo, iCloud e Zoho a partir do domínio do teu email; para outros domínios tenta um padrão corporativo comum. Se os teus dados de acesso falharem por qualquer motivo, o email é enviado na mesma através da SUDOMAKE — a resposta continua com status: true, mas o campo log explica exactamente o que falhou nos teus dados e diz que foi usado o protocolo padrão.
Todos os anexos são analisados antes do envio (VirusTotal + lista de tipos de ficheiro seguros). Se um anexo for identificado como malicioso, o email não é enviado, a tua conta é suspensa automaticamente e recebes um email a explicar o motivo.

Parâmetros

Campo Tipo Descrição
api_key string obrigatório A tua chave de API encriptada.
email string obrigatório O teu email (usado como login SMTP e como remetente, se o envio for bem-sucedido).
password string obrigatório A password/app-password da tua conta de email.
smtp_host string opcional Servidor SMTP. Deixa vazio para deteção automática pelo domínio do email.
smtp_port integer opcional Porta SMTP (465 = SSL, 587 = STARTTLS).
remetente string obrigatório Nome de exibição do remetente.
destinatario string obrigatório Email de destino.
assunto string obrigatório Assunto do email.
mensagem string obrigatório Corpo do email.
anexos[] file[] opcional Um ou mais ficheiros anexos (máx. 5MB cada).

Exemplo de pedido

curl -X POST "https://smsapi.sudomakes.com/api/enviar-email" \
  -F "api_key=a_tua_chave_encriptada" \
  -F "email=tu@teudominio.com" \
  -F "password=a_tua_password" \
  -F "remetente=A Tua Empresa" \
  -F "destinatario=cliente@exemplo.com" \
  -F "assunto=Confirmação de encomenda" \
  -F "mensagem=Olá! A tua encomenda foi enviada." \
  -F "anexos[]=@fatura.pdf"
const dados = new FormData();
dados.append("api_key", "a_tua_chave_encriptada");
dados.append("email", "tu@teudominio.com");
dados.append("password", "a_tua_password");
dados.append("remetente", "A Tua Empresa");
dados.append("destinatario", "cliente@exemplo.com");
dados.append("assunto", "Confirmação de encomenda");
dados.append("mensagem", "Olá! A tua encomenda foi enviada.");
dados.append("anexos[]", ficheiroInput.files[0]);

fetch("https://smsapi.sudomakes.com/api/enviar-email", {
  method: "POST",
  body: dados,
})
  .then((res) => res.json())
  .then((resposta) => console.log(resposta));
var dados = new FormData();
dados.append("api_key", "a_tua_chave_encriptada");
dados.append("email", "tu@teudominio.com");
dados.append("password", "a_tua_password");
dados.append("remetente", "A Tua Empresa");
dados.append("destinatario", "cliente@exemplo.com");
dados.append("assunto", "Confirmação de encomenda");
dados.append("mensagem", "Olá! A tua encomenda foi enviada.");

$.ajax({
  url: "https://smsapi.sudomakes.com/api/enviar-email",
  method: "POST",
  data: dados,
  processData: false,
  contentType: false,
  success: function (resposta) {
    console.log(resposta);
  }
});
const dados = new FormData();
dados.append("api_key", "a_tua_chave_encriptada");
dados.append("email", "tu@teudominio.com");
dados.append("password", "a_tua_password");
dados.append("remetente", "A Tua Empresa");
dados.append("destinatario", "cliente@exemplo.com");
dados.append("assunto", "Confirmação de encomenda");
dados.append("mensagem", "Olá! A tua encomenda foi enviada.");

const resposta = await fetch("https://smsapi.sudomakes.com/api/enviar-email", {
  method: "POST",
  body: dados,
});
console.log(await resposta.json());
$ch = curl_init('https://smsapi.sudomakes.com/api/enviar-email');
curl_setopt_array($ch, [
    CURLOPT_POST => true,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_POSTFIELDS => [
        'api_key' => 'a_tua_chave_encriptada',
        'email' => 'tu@teudominio.com',
        'password' => 'a_tua_password',
        'remetente' => 'A Tua Empresa',
        'destinatario' => 'cliente@exemplo.com',
        'assunto' => 'Confirmação de encomenda',
        'mensagem' => 'Olá! A tua encomenda foi enviada.',
        'anexos[0]' => new CURLFile('fatura.pdf'),
    ],
]);
$resposta = json_decode(curl_exec($ch), true);
import requests

resposta = requests.post(
    "https://smsapi.sudomakes.com/api/enviar-email",
    data={
        "api_key": "a_tua_chave_encriptada",
        "email": "tu@teudominio.com",
        "password": "a_tua_password",
        "remetente": "A Tua Empresa",
        "destinatario": "cliente@exemplo.com",
        "assunto": "Confirmação de encomenda",
        "mensagem": "Olá! A tua encomenda foi enviada.",
    },
    files={"anexos[]": open("fatura.pdf", "rb")},
)
print(resposta.json())
HttpClient client = HttpClient.newHttpClient();
var boundary = "----boundary" + System.currentTimeMillis();
var body = "--" + boundary + "\r\n"
    + "Content-Disposition: form-data; name=\"api_key\"\r\n\r\na_tua_chave_encriptada\r\n"
    + "--" + boundary + "\r\n"
    + "Content-Disposition: form-data; name=\"email\"\r\n\r\ntu@teudominio.com\r\n"
    + "--" + boundary + "\r\n"
    + "Content-Disposition: form-data; name=\"password\"\r\n\r\na_tua_password\r\n"
    + "--" + boundary + "\r\n"
    + "Content-Disposition: form-data; name=\"remetente\"\r\n\r\nA Tua Empresa\r\n"
    + "--" + boundary + "\r\n"
    + "Content-Disposition: form-data; name=\"destinatario\"\r\n\r\ncliente@exemplo.com\r\n"
    + "--" + boundary + "\r\n"
    + "Content-Disposition: form-data; name=\"assunto\"\r\n\r\nConfirmação de encomenda\r\n"
    + "--" + boundary + "\r\n"
    + "Content-Disposition: form-data; name=\"mensagem\"\r\n\r\nOlá! A tua encomenda foi enviada.\r\n"
    + "--" + boundary + "--\r\n";

HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://smsapi.sudomakes.com/api/enviar-email"))
    .header("Content-Type", "multipart/form-data; boundary=" + boundary)
    .POST(HttpRequest.BodyPublishers.ofString(body))
    .build();

HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());

Resposta de sucesso (com os teus dados de acesso)

{
  "status": true,
  "log": "Email enviado com sucesso.",
  "metodo": "proprio"
}

Resposta de sucesso (fallback — os teus dados falharam)

{
  "status": true,
  "log": "Email enviado com sucesso (usado o protocolo padrão da plataforma porque os dados de acesso indicados falharam: autenticação SMTP falhou — usuário/password incorrectos).",
  "metodo": "fallback"
}

Resposta de erro (anexo bloqueado)

{
  "status": false,
  "log": "Conta suspensa: anexo bloqueado por segurança (tipo de ficheiro não permitido). Confirma que o ficheiro não está infectado e usa apenas os tipos permitidos (pdf, jpg, jpeg, png, docx, xlsx, csv, txt) com no máximo 5MB cada. Depois de resolvido, contacta comercial@sudomakes.com para reactivares a conta."
}

Códigos de erro comuns

Em todos os endpoints, o campo com a mensagem de erro (erro, log ou otp, conforme o caso) explica sempre o motivo específico da falha e o que fazer para a resolver — os exemplos abaixo mostram apenas a causa resumida.

HTTP Campo Causa
401 erro: "Chave de API inválida." A api_key enviada não pôde ser decifrada.
401 erro: "Sem autorização para utilizar esta chave." Esta api_key não existe ou a chave já foi revogada.
403 erro: "...não está autorizado..." A chave está limitada por domínio e o pedido (feito a partir de um browser) veio de um domínio que não está registado para essa chave em "Chaves" no Dashboard.
403 erro: "Conta suspensa." A conta foi suspensa (ex: anexo malicioso, tentativa de impersonação de marca). O email enviado à conta explica o motivo.
403 log/otp: "Sem créditos..." Saldo insuficiente para o custo deste envio. A mensagem já indica o custo, o saldo actual e o link para recarregar.
403 log/otp: "Mensagem bloqueada..." A IA de moderação da SUDOMAKE detectou uma tentativa de impersonar outra empresa no texto.
403 log: "...anexo bloqueado..." Um anexo do /api/enviar-email foi identificado como malicioso ou tem um tipo de ficheiro não permitido.
502 log: "Falha ao enviar o email..." As credenciais SMTP indicadas falharam e o envio pela SUDOMAKE (fallback) também não foi possível.
422 errors: {...} Faltam campos obrigatórios no pedido.

Sandbox

Testa qualquer endpoint em tempo real com a tua própria api_key e vê logo o código equivalente na linguagem que preferires.

Este sandbox faz o pedido directamente a partir desta página (smsapi.sudomakes.com), por isso, se usares uma chave limitada por domínio, precisas de ter este domínio registado para essa chave em "Chaves" no teu Dashboard — ou usa uma chave sem restrição de domínio.

Pedido

POST /api/enviar-sms
Atenção: isto envia mesmo uma mensagem real e consome saldo da tua conta.

Nunca partilhes a tua api_key publicamente — este teste corre só no teu browser.

Resposta
A resposta ao pedido aparece aqui depois de clicares em "Testar agora".

Código equivalente