GUÍA PARA DESARROLLADORES

Cómo enviar SMS desde C# y .NET con la API de Grupo Tecnophone

Integre el envío de SMS en su aplicación .NET con HttpClient y una petición HTTPS: autenticación por token, IP autorizada y respuesta JSON con el identificador de cada mensaje.

Antes de empezar

  • Una conexión API creada en el panel web (app.grupotecnophone.com), con su Bearer Token de sandbox o de producción.
  • La IP pública de su servidor registrada como autorizada para ese token.
  • Un User-Agent que identifique a su aplicación, por ejemplo MiEmpresa/1.0.
  • .NET 6 o superior. Los ejemplos usan HttpClient y System.Text.Json, que ya vienen incluidos: no hace falta instalar paquetes NuGet.

Guarde el token en una variable de entorno (en estos ejemplos, GTP_SMS_TOKEN) o en el almacén de secretos de su plataforma, y nunca lo incluya en una app móvil, de escritorio o en el frontend: las llamadas a la API deben salir siempre de su backend, desde una IP autorizada.

Enviar un SMS con C# y HttpClient

El siguiente programa de consola envía un SMS y procesa la respuesta:

using System.Net.Http.Headers;
using System.Net.Http.Json;
using System.Text.Json;

var token = Environment.GetEnvironmentVariable("GTP_SMS_TOKEN")
    ?? throw new InvalidOperationException("Falta la variable GTP_SMS_TOKEN");

using var http = new HttpClient { Timeout = TimeSpan.FromSeconds(30) };
http.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
http.DefaultRequestHeaders.UserAgent.ParseAdd("MiEmpresa/1.0");

var payload = new
{
    to = "+525512345678",
    body = "Su codigo de verificacion es 482913. Vence en 5 minutos."
};

using var response = await http.PostAsJsonAsync(
    "https://api.grupotecnophone.com/prod/v1/sms/send", payload);

var json = await response.Content.ReadAsStringAsync();
using var doc = JsonDocument.Parse(json);
var root = doc.RootElement;

if (response.IsSuccessStatusCode
    && root.TryGetProperty("status", out var status)
    && status.GetString() == "success")
{
    Console.WriteLine($"Enviado. SID: {root.GetProperty("sid").GetString()} - segmentos: {root.GetProperty("num_segments").GetInt32()}");
}
else
{
    var code = root.TryGetProperty("error", out var error) && error.ValueKind == JsonValueKind.Object
        ? error.GetProperty("code").GetString()
        : $"HTTP_{(int)response.StatusCode}";
    Console.WriteLine($"No enviado ({code}): {json}");
}

Respuesta de la API

Si el mensaje fue aceptado, la API responde con HTTP 200 y un JSON como este:

{
  "sid": "sms_20261012143201_39bdafbd",
  "status": "success",
  "to": "+525512345678",
  "body": "Su codigo de verificacion es 482913. Vence en 5 minutos.",
  "encoding": "GSM7",
  "num_chars": 56,
  "num_segments": 1,
  "error": null
}

Guarde el sid: es el identificador con el que podrá conciliar el reporte de entrega del mensaje. El campo num_segments indica cuántos segmentos se cobrarán; vea cómo se calculan los segmentos.

Enviar SMS a varios destinatarios con C#

Para enviar SMS masivos desde .NET conviene encapsular la llamada en una clase y reutilizar el mismo HttpClient. Así guarda el sid de cada mensaje y separa los errores.

using System.Net.Http.Json;
using System.Text.Json;

public sealed record SmsResult(bool Ok, string? Sid, string? Error);

public sealed class GtpSmsClient
{
    private const string Endpoint = "https://api.grupotecnophone.com/prod/v1/sms/send";
    private readonly HttpClient _http;

    // Reciba un HttpClient ya configurado con el token, el User-Agent y el timeout
    public GtpSmsClient(HttpClient http) => _http = http;

    public async Task<SmsResult> SendAsync(string to, string body, CancellationToken ct = default)
    {
        using var response = await _http.PostAsJsonAsync(Endpoint, new { to, body }, ct);
        var json = await response.Content.ReadAsStringAsync(ct);
        try
        {
            using var doc = JsonDocument.Parse(json);
            var root = doc.RootElement;
            if (response.IsSuccessStatusCode
                && root.TryGetProperty("status", out var s) && s.GetString() == "success")
            {
                return new SmsResult(true, root.GetProperty("sid").GetString(), null);
            }
            var code = root.TryGetProperty("error", out var e) && e.ValueKind == JsonValueKind.Object
                ? e.GetProperty("code").GetString()
                : null;
            return new SmsResult(false, null, code ?? $"HTTP_{(int)response.StatusCode}");
        }
        catch (JsonException)
        {
            return new SmsResult(false, null, $"HTTP_{(int)response.StatusCode}");
        }
    }
}

// Uso: recorrer la lista a un ritmo moderado y guardar el sid de cada mensaje
var sms = new GtpSmsClient(http);
string[] destinatarios = { "+525512345678", "+528112345678" };

foreach (var numero in destinatarios)
{
    var r = await sms.SendAsync(numero, "Su pedido fue enviado. Gracias por su compra.");
    Console.WriteLine(r.Ok ? $"{numero}: {r.Sid}" : $"{numero}: error {r.Error}");
    await Task.Delay(200);
}

En ASP.NET Core registre la clase con builder.Services.AddHttpClient<GtpSmsClient>() y configure ahí el token, el User-Agent y el timeout. Para volúmenes altos, encole los envíos en un servicio en segundo plano. Sin programar, también puede enviar SMS masivos desde Excel o CSV.

Enviar un código OTP con C#

Genere el código con RandomNumberGenerator, que es criptográficamente seguro, guarde solo su hash y compárelo en tiempo constante.

using System.Security.Cryptography;
using System.Text;

// Código de 6 dígitos con un generador criptográficamente seguro
var codigo = RandomNumberGenerator.GetInt32(0, 1_000_000).ToString("D6");

// Guarde solo el hash, con vencimiento y número máximo de intentos
var hash = SHA256.HashData(Encoding.UTF8.GetBytes($"{usuarioId}:{codigo}"));
await repositorio.GuardarOtpAsync(usuarioId, hash, DateTimeOffset.UtcNow.AddMinutes(5));

var r = await sms.SendAsync(telefono,
    $"Su codigo de verificacion es {codigo}. Vence en 5 minutos. No lo comparta.");

// Al validar, compare los hashes en tiempo constante
bool EsValido(byte[] guardado, string ingresado) =>
    CryptographicOperations.FixedTimeEquals(
        guardado, SHA256.HashData(Encoding.UTF8.GetBytes($"{usuarioId}:{ingresado}")));

Más detalles del flujo en la guía de autenticación OTP por SMS y en nuestro servicio de OTP por SMS para empresas.

Errores frecuentes

HTTPCódigoQué significa
400ENCRYPTION_REQUIREDLa conexión exige que to y body viajen cifrados con RSA-OAEP
400ENCRYPTION_NOT_ALLOWEDLa conexión opera en texto plano y se recibió contenido cifrado
400INPUT_PHONE_BLACKLISTEDEl número de destino está en lista negra
400INSUFFICIENT_BALANCESaldo insuficiente para el envío
401—Token ausente o inválido
403—La IP de origen no está autorizada para el token
500—Error interno no esperado

En los errores 400 la respuesta incluye un objeto error con code, code_num y message.

Probar en sandbox

Cambie el endpoint por https://api.grupotecnophone.com/test/v1/sms/send y use el token de sandbox. Ese entorno valida token, IP, payload y cifrado con la misma lógica que producción, pero no envía SMS reales.

Buenas prácticas

  • Defina un timeout y registre cada respuesta con su sid.
  • Ante un error de red sin respuesta, no reenvíe a ciegas: verifique primero para no duplicar el mensaje al usuario.
  • Reintente solo errores 500, con espera progresiva y un número máximo de intentos.
  • Encole los envíos masivos en lugar de enviarlos en el ciclo de una petición web.
  • Si el contenido es sensible, active el cifrado de la conexión; la documentación de la API describe el formato de cifrado RSA-OAEP.

Vea también la API SMS México, la conexión SMPP y las guías para PHP, Laravel, Python, Node.js, Java y cURL. Si necesita credenciales de prueba, contáctenos.

Preguntas frecuentes: Enviar SMS con C# y .NET

Scroll al inicio