SMS por SMPP 3.4
Conecta tu plataforma al servidor SMPP 3.4 de Hablame para enviar SMS y recibir, por cada mensaje, el estado final que conocemos de él.
12 min de lecturaRevisado el
Objetivo
Enviar SMS desde tu propia plataforma con el protocolo estándar SMPP 3.4, y saber qué pasó con cada uno. Es la vía indicada si ya tienes un cliente SMPP o necesitas enviar en volumen sostenido.
Por SMPP envías y recibes los acuses de entrega de lo que enviaste. Los SMS que las personas le escriben a tu código corto no llegan por aquí: llegan por webhook.
Requisitos
- Una cuenta SMPP creada por el equipo de Hablame. Cómo pedirla.
- IP públicas fijas: solo las que autorices quedan habilitadas para tu cuenta.
- Un centro de costo al que se atribuye el consumo.
- Un cliente SMPP 3.4 (
interface_version0x34). Si quieres acuses, una conexiónreceiverotransceiver.
Credenciales
Soporte crea tu cuenta y te entrega el servidor, el puerto, tu system_id (hasta 15 caracteres) y tu contraseña (hasta 8 caracteres, el máximo que permite SMPP 3.4). No se publican en este portal.
El mismo puerto atiende conexiones con y sin cifrado: si tu cliente abre con TLS (versión 1.2 o superior), el servidor lo detecta solo. Te recomendamos TLS.
system_type, addr_ton, addr_npi y address_range del bind se aceptan pero no se validan.
Pasos
- 01Abre la conexión y haz el bind
Envía el primer byte en menos de 5 s; si usas TLS, completa el saludo en menos de 10 s. El bind debe llegar en menos de 10 s y, en total, antes de 30 s desde que abriste la conexión.
- 02Envía con submit_sm
Por una conexión
transmitterotransceiver. Ponregistered_deliveryen 0x01 si quieres el acuse de cada mensaje. - 03Guarda el message_id
Llega en el
submit_sm_resp. Es el mismo que trae el acuse, carácter por carácter. - 04Recibe y confirma los acuses
Llegan como
deliver_smpor tus conexionesreceiverotransceiverde la misma cuenta. Responde cada uno condeliver_sm_respy estado 0 en menos de 60 s.
| Comando | Para qué |
|---|---|
bind_transmitter | Abre una conexión para enviar. |
bind_receiver | Abre una conexión para recibir acuses de entrega. |
bind_transceiver | Abre una conexión para las dos cosas. |
submit_sm | Envía un mensaje (o una parte de un mensaje largo). |
enquire_link | Comprueba que la conexión sigue viva. |
deliver_sm_resp | Confirma un acuse que te enviamos. |
unbind | Cierra la conexión de forma ordenada. |
unbind_resp | Responde a un unbind que te enviamos. |
No se admiten query_sm, submit_multi, data_sm, replace_sm, cancel_sm: responden generic_nack con 0x00000003 y la conexión sigue abierta.
Mantener la conexión
- Hablame te envía un
enquire_linkcada 30 s, haya tráfico o no. Respóndelo siempre: con 2 seguidos sin respuesta, la conexión se cierra. - Si tu cliente deja de leer durante 30 s, la conexión se cierra.
- Puedes enviar tus propios
enquire_link, pero solo después del bind: antes reciben 0x00000004. - Para cerrar, envía
unbindy espera su respuesta.
Límites
| Qué | Límite | Al superarlo |
|---|---|---|
| Conexiones simultáneas por IP y cuenta | 20 | Se cierra la más antigua para abrir la nueva. Si la nueva es transmitter y la que habría que cerrar es la última que recibe acuses, se rechaza la nueva con 0x00000005. |
| Conexiones simultáneas desde una misma IP | 64 | La conexión nueva se cierra de inmediato. |
submit_sm por segundo en cada conexión | 3.000 | Respuesta 0x00000058. Cada parte de un mensaje largo cuenta como un submit_sm. |
| Tamaño de un PDU | 64 KiB | generic_nack con 0x00000002 y se cierra la conexión. |
Binds fallidos por minuto, por IP y system_id | 5 | El resto de ese minuto, todo bind recibe 0x0000000D. |
Ejemplos
Campos de submit_sm
source_addr- El remitente, hasta 20 caracteres.
destination_addr- El número de destino, hasta 20 caracteres. Obligatorio: sin él, 0x0000000B.
esm_class- 0x40 si el texto empieza con una cabecera UDH.
registered_delivery- 0x01: acuse con el estado final, sea cual sea. 0x02: acuse solo si el mensaje falla. 0x00: sin acuse. No hay notificaciones intermedias.
data_coding- La codificación del texto (tabla de abajo).
short_message- El texto, hasta 254 octetos. Si el texto es más largo, usa
message_payload; si llegan los dos, se usashort_message. schedule_delivery_time- Hoy no se aplica: el mensaje sale de inmediato. No lo uses para programar envíos.
validity_period- Se acepta y se guarda tal como llega.
Codificación
En SMPP el texto GSM-7 va sin empaquetar: un carácter por octeto. Si lo empaquetas, llega ilegible.
data_coding | Codificación | Mensaje de una parte | Cada parte de un mensaje largo |
|---|---|---|---|
0x00 | GSM-7, sin empaquetar (un carácter por octeto) | 160 caracteres | 153 caracteres |
0x01 | ASCII | 160 caracteres | 153 caracteres |
0x03 | Latin-1 (ISO-8859-1) | 160 caracteres | 153 caracteres |
0x04 | Binario | 140 octetos | 134 octetos |
0x08 | UCS-2 (big endian) | 70 caracteres | 67 caracteres |
- En GSM-7 caben
ñ,Ñ,é,É,ü,Ü,¿,¡. Las vocales con tildeá,í,ó,ú,Á,Í,Ó,Úno caben: un texto con ellas va en UCS-2 (0x08). - En GSM-7,
€,[,],{,},~,\,^,|ocupan dos caracteres cada uno. - En UCS-2, un emoji fuera del plano básico ocupa dos caracteres.
Mensajes largos
Tienes dos formas de enviar un texto que no cabe en una parte:
- Partirlo tú, con una cabecera UDH de concatenación (IEI 0x00 con referencia de 8 bits o 0x08 con referencia de 16 bits) y
esm_class0x40, o con los TLVsar_msg_ref_num,sar_total_segmentsysar_segment_seqnumsi no usas UDH. Si llegan las dos cosas, manda la UDH. - Enviarlo entero en el TLV
message_payload, sin UDH, dentro del límite de 64 KiB por PDU.
Si lo partes tú, el servidor junta las partes antes de enviarlo: espera hasta 60 minutos desde la primera y admite hasta 255 partes. Las partes se reconocen por organización, referencia, total y destino, así que puedes enviarlas por conexiones distintas de la misma organización. Cada parte recibe su propio message_id y su propio acuse.
Un acuse de ejemplo
id:0192f0c4-7b1e-7a3d-9c55-3e2a1b4c5d6e sub:001 dlvrd:001 submit date:2610241004 done date:2610241004 stat:DELIVRD err:000 Text:Hola Ana, tu pedido Respuestas esperadas
submit_sm_resp
Con estado 0 trae el message_id: un UUID versión 7 de 36 caracteres, uno por PDU, incluida cada parte de un mensaje largo. Con otro estado, el mensaje no se aceptó: mira la tabla de command_status.
Acuses de entrega
Un acuse es el estado final que conocemos de tu mensaje. No garantiza que la persona lo haya leído.
- Llega como
deliver_smconesm_class0x04, con las direcciones invertidas:source_addres el teléfono al que enviaste ydestination_addr, tu remitente. - Hay un acuse por parte.
subydlvrdsiempre valen001. submit datees cuando aceptamos el mensaje ydone date, cuando se supo el desenlace, los dos en hora de Colombia (UTC−5).Text:trae los primeros 20 caracteres imprimibles ASCII del mensaje, así que en UCS-2 puede quedar casi vacío.- Lee el estado mejor de los TLV que del texto: el texto es informativo y los TLV son la forma normalizada. No se devuelve
user_message_reference.
id:<message_id> sub:001 dlvrd:001 submit date:AAMMDDhhmm done date:AAMMDDhhmm stat:<estado> err:<error> Text:<texto>stat: | message_state | Qué significa | ¿Llega con 0x02? |
|---|---|---|---|
DELIVRD | 2 | Entregado. | No |
EXPIRED | 3 | Venció sin entregarse. | Sí |
DELETED | 4 | Borrado. | Sí |
UNDELIV | 5 | No se pudo entregar. | Sí |
ACCEPTD | 6 | Aceptado. | No |
UNKNOWN | 7 | Estado desconocido. | Sí |
REJECTD | 8 | Rechazado. | Sí |
| TLV | Etiqueta | Uso |
|---|---|---|
message_payload | 0x0424 | Lo lee en submit_sm: el texto, cuando no cabe en short_message. Si llegan los dos, se usa short_message. |
sar_msg_ref_num | 0x020C | Lo lee en submit_sm: referencia de un mensaje largo, si no usas UDH. |
sar_total_segments | 0x020E | Lo lee en submit_sm: total de partes. |
sar_segment_seqnum | 0x020F | Lo lee en submit_sm: número de esta parte, desde 1. |
receipted_message_id | 0x001E | Siempre en el acuse: el message_id del mensaje. |
message_state | 0x0427 | Siempre en el acuse: el estado, como número (tabla de estados). |
Cómo te llegan los acuses
- Cada conexión que recibe arranca con 5 acuses sin confirmar a la vez y puede subir hasta 50 si respondes rápido.
- Si no respondes un
deliver_smen 60 s, o respondes con un estado distinto de 0, el acuse se vuelve a enviar. Puede llegarte repetido: descarta los repetidos porreceipted_message_id. - Si no tienes ninguna conexión que reciba, los acuses esperan y se siguen intentando hasta 72 horas.
Errores habituales
Las respuestas más frecuentes y qué hacer. La lista completa está en Códigos command_status.
| Código | Cuándo | Qué hacer |
|---|---|---|
0x00000001 ESME_RINVMSGLEN | El submit_sm está mal formado, o no trae texto ni en short_message ni en message_payload. | Revisa cómo arma el PDU tu cliente. No lo reintentes igual. |
0x00000004 ESME_RINVBNDSTS | El comando no corresponde al estado de la conexión: llegó antes de un bind exitoso (incluido enquire_link), o es un submit_sm por una conexión receiver. | Haz el bind primero, y envía por una conexión transmitter o transceiver. Un unbind sin bind recibe este código y además cierra la conexión. |
0x0000000A ESME_RINVSRCADR | Te conectaste desde una IP que no está autorizada para tu cuenta. | Pide a soporte que autorice esa IP. |
0x0000000D ESME_RBINDFAIL | La contraseña es incorrecta, el bind está mal formado (y se cierra la conexión), o hubo demasiados intentos fallidos: tras 5 en un minuto desde la misma IP y el mismo system_id, el resto de ese minuto recibe este código aunque la contraseña sea correcta. | Revisa la contraseña y espera al minuto siguiente antes de reintentar. |
0x00000058 ESME_RTHROTTLED | Superaste 3.000 submit_sm por segundo en esa conexión, o Hablame está frenando la entrada por un momento para protegerse. | Baja el ritmo y reintenta ese mensaje con espera. La conexión sigue abierta. |
Seguridad
- SMPP 3.4 limita la contraseña a 8 caracteres. Por eso tu cuenta solo acepta conexiones desde las IP que autorizaste, y un bind desde otra recibe 0x0000000A.
- Tras 5 binds fallidos en un minuto desde la misma IP y el mismo
system_id, el resto del minuto se rechaza. - Usa TLS 1.2 o superior para que la contraseña y los mensajes no viajen en claro.
- Guarda la contraseña en tu gestor de secretos y nunca la envíes por correo. Si crees que se filtró, escribe a developers@hablame.co.
Endpoints relacionados
SMPP no usa la API REST: no hay endpoints relacionados. Los SMS entrantes llegan por webhook.