tutorial · PHP e cURL

Como enviar SMS com PHP e cURL

Integre o envio de SMS ao seu servidor PHP com uma requisição HTTPS. Aprenda a preparar o JSON, tratar erros e consultar a entrega da mensagem.

1. Prepare o ambiente PHP

O exemplo usa PHP 8 ou superior com a extensão cURL habilitada. Você também precisa de uma conta no SMS Fácil, de créditos para enviar e de um número autorizado para o teste.

Confira sua instalação com php --version e a presença de curl em php -m. O servidor precisa conseguir acessar HTTPS com certificados válidos; mantenha a verificação TLS habilitada.

Configure SMSFACIL_USUARIO, SMSFACIL_SENHA e SMSFACIL_DESTINO nas variáveis de ambiente do processo PHP. Use DDD + número, somente dígitos, com 10 ou 11 posições e sem +55.

As credenciais devem ficar no servidor, fora do repositório e de páginas públicas. Configure os segredos pelo painel da hospedagem ou pelo ambiente de execução.

2. Envie uma mensagem com PHP e cURL

Crie o arquivo enviar-sms.php. A função abaixo envia JSON no corpo e retorna o texto da resposta, permitindo reutilizá-la na consulta de status.

enviar-sms.php
<?php
function config(string $nome): string
{
    $valor = getenv($nome);
    if ($valor === false || trim($valor) === '') {
        throw new RuntimeException("Configure {$nome}.");
    }
    return $valor;
}

function postJson(string $endpoint, array $dados): string
{
    $json = json_encode($dados, JSON_THROW_ON_ERROR);
    $ch = curl_init('https://www.smsfacil.com.br/api/v2/' . $endpoint);
    if ($ch === false) {
        throw new RuntimeException('Não foi possível iniciar cURL.');
    }
    try {
        curl_setopt_array($ch, [
            CURLOPT_POST => true,
            CURLOPT_POSTFIELDS => $json,
            CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_CONNECTTIMEOUT => 10,
            CURLOPT_TIMEOUT => 60,
        ]);
        $corpo = curl_exec($ch);
        if ($corpo === false) {
            throw new RuntimeException('Falha de conexão; resultado não confirmado.');
        }
        $http = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        if ($http < 200 || $http >= 300) {
            throw new RuntimeException("HTTP {$http}; verifique antes de reenviar.");
        }
        return $corpo;
    } finally {
        curl_close($ch);
    }
}

$usuario = config('SMSFACIL_USUARIO');
$senha = config('SMSFACIL_SENHA');
$destino = config('SMSFACIL_DESTINO');

try {
    $corpo = postJson('EnviaSMS', [
        'usuario' => $usuario,
        'senha' => $senha,
        'mensagens' => [
            ['para' => $destino, 'texto' => 'Sua consulta e amanha as 10h.'],
        ],
    ]);
    $resposta = json_decode($corpo, true, 512, JSON_THROW_ON_ERROR);
    if (!is_array($resposta) || !isset($resposta['resultados'])
        || !is_array($resposta['resultados'])) {
        throw new RuntimeException('Resposta inesperada; resultado não confirmado.');
    }
    foreach ($resposta['resultados'] as $item) {
        $resultado = $item['resultado'] ?? '';
        if (($item['sucesso'] ?? false) === true
            && str_starts_with($resultado, 'OK ')) {
            $pedido = trim(substr($resultado, 3));
            echo "Aceito na fila. Pedido: {$pedido}" . PHP_EOL;
            // Persista o pedido junto ao evento de negócio.
        } else {
            echo "Falha no item {$item['indice']}: {$resultado}" . PHP_EOL;
        }
    }
} catch (RuntimeException | JsonException $e) {
    fwrite(STDERR, $e->getMessage() . ' Não reenvie automaticamente.' . PHP_EOL);
    exit(1);
}

Execute php enviar-sms.php uma vez pelo terminal. O script faz um envio real, sujeito à cobrança de créditos. Não o exponha como uma página pública que dispara mensagens a cada acesso.

3. Trate o resultado além do HTTP 200

O envio retorna JSON. HTTP 200 pode incluir falhas individuais: confira sucesso e resultado em cada item. O exemplo guarda o número da solicitação na variável $pedido quando o resultado começa com OK .

Os códigos -7 e -8 indicam, respectivamente, falta de créditos e credenciais inválidas. HTTP 400 indica um problema no corpo da requisição e HTTP 415 indica formato de conteúdo incompatível. Veja todos os erros e limites da API.

Não repita o envio automaticamente após uma falha de conexão. O SMS pode já estar na fila mesmo sem resposta. A API não deduplica requisições. Confira o histórico no painel ou procure o suporte quando não tiver recebido um número de solicitação.

4. Consulte a entrega com o recibo

Em uma operação posterior, reutilize a função postJson e as credenciais do exemplo. Substitua o marcador pelo número retornado no envio. A consulta retorna texto simples, portanto não use json_decode aqui.

PHP · consulta de status
$pedidoSalvo = 'NUMERO_RETORNADO_NO_ENVIO';
try {
    $status = postJson('consultaenvio', [
        'usuario' => $usuario,
        'senha' => $senha,
        'nr_pedido' => $pedidoSalvo,
    ]);
    echo $status . PHP_EOL; // Texto simples, não JSON.
} catch (RuntimeException $e) {
    fwrite(STDERR, 'Não foi possível consultar o status.' . PHP_EOL);
}

O resultado pode ser Pendente, Enviada, Entregue ou outro status documentado. Uma mensagem aceita ainda pode não ter sido entregue, e entrega não significa leitura.

Antes de usar em produção

  • Salve o número da solicitação no banco junto ao evento que motivou o SMS.
  • Em um lote de até 1.000 mensagens, registre cada resultado; falhas não desfazem itens já aceitos.
  • Para agendar, inclua data (dd/mm/aaaa) e hora (hh:mm) no item da mensagem, usando o horário de Brasília. Uma data passada provoca envio imediato.
  • Não registre o corpo completo das requisições em logs, pois ele contém a senha.
  • Respeite os termos de uso: mensagens solicitadas pelo destinatário e sem URLs, links ou endereços eletrônicos.

Seu projeto usa .NET? Siga o tutorial de envio de SMS com C#.

Conecte seu projeto PHP ao SMS Fácil

Crie sua conta, adquira créditos e faça o primeiro envio pelo seu servidor.

Criar conta grátis

cadastro grátis · sem cartão · créditos sem validade

Demonstração de envio.

Reconectando ao servidor...

Falha na reconexão... tentando novamente em segundos.

Falha ao reconectar.
Por favor, tente novamente ou recarregue a página.

A sessão foi pausada pelo servidor.

Falha ao retomar a sessão.
Por favor, recarregue a página.