API de supresiones
La API de supresiones gestiona las listas, por espacio de trabajo, de direcciones de email y números de teléfono a los que Joryio no enviará mensajes. Una supresión es un bloqueo estricto: mientras un identificador esté suprimido en un canal, se omite cualquier mensaje a ese identificador en ese canal, sin importar qué campaña o journey intente alcanzarlo.
Esta API refleja la sección Audiencia → Listas de supresión del dashboard. Úsala para auditar quién está suprimido, migrar una lista existente de direcciones inactivas desde otra plataforma, cumplir una solicitud de consentimiento de tus propios sistemas o eliminar una supresión después de resolver un rebote permanente.
Todos los endpoints de esta página son relativos a la URL base: https://api-eu1.joryio.com. Consulta el resumen de la API.
Autenticación
Cada solicitud se autentica con una clave de API que tenga el scope de entregabilidad correspondiente o con una sesión del dashboard (JWT). Los datos de supresión tienen ámbito de espacio de trabajo: una clave solo puede ver y editar las listas de su propio espacio de trabajo.
Authorization: Bearer jry_live_your_api_key_here
Content-Type: application/json
Scopes por endpoint
El canal determina el scope necesario. Los endpoints de email necesitan email_suppression:*; los de SMS y WhatsApp necesitan sms_suppression:*.
| Endpoint | Canal email | Canal SMS / WhatsApp |
|---|---|---|
GET /suppressions | email_suppression:read | sms_suppression:read |
GET /suppressions/{identifier} | email_suppression:read | sms_suppression:read |
POST /suppressions | email_suppression:write | sms_suppression:write |
POST /suppressions/hard-bounce | email_suppression:write | - (email only) |
POST /suppressions/import | email_suppression:write | sms_suppression:write |
DELETE /suppressions/{identifier} | email_suppression:write | sms_suppression:write |
Conceptos básicos
Lee esta sección antes de llamar a los endpoints de escritura: el resto de la API solo tiene sentido una vez que está clara la separación entre reason y source.
reason (por qué) frente a source (de dónde procede)
Cada fila de supresión tiene dos campos independientes:
reason: por qué se suprime el identificador. Puede serunsubscribe,hard_bounce,complaintomanual.source: de dónde procede la supresión. Puede serdelivery,api,importo una fuente de consentimiento comounsubscribe_link.
Son conceptos independientes. Un mismo reason puede provenir de fuentes distintas: un hard_bounce observado por nuestra propia canalización de envío tiene source: "delivery", mientras que un hard_bounce que declares mediante esta API tiene source: "api". El motivo indica su significado de entregabilidad o consentimiento; la fuente te dice en qué medida confiar en él y si cuenta para tus métricas de reputación.
Motivos de consentimiento frente a motivos de entregabilidad
Los cuatro motivos se dividen en dos familias que se comportan de forma diferente:
| Familia | Motivos | Significado | ¿Sobrevive a una nueva suscripción? |
|---|---|---|---|
| Consentimiento | unsubscribe, manual | El destinatario, o tú en su nombre, pidió no recibir comunicaciones. | No: una nueva aceptación lo elimina. |
| Entregabilidad | hard_bounce, complaint | La dirección o el número ya no es válido o nos marcó como spam. | Sí: persiste incluso si el destinatario vuelve a suscribirse. |
Una supresión de entregabilidad es un hecho técnico sobre la dirección, no una preferencia; por eso, que el destinatario se suscriba de nuevo no la elimina. Solo se elimina mediante una acción explícita del operador: DELETE /suppressions/{identifier}, «borrar rebote» en el dashboard o el cambio del contacto a una dirección de email nueva.
No se puede inventar un rebote
Las rutas de escritura habituales, POST /suppressions y POST /suppressions/import, restringen reason a manual o unsubscribe. No pueden crear una fila hard_bounce ni complaint. Un rebote es algo que la plataforma observa, no algo que un cliente pueda declarar sin más.
La única ruta que puede declarar un rebote es POST /suppressions/hard-bounce y, aun así, la fila lleva source: "api", para que nunca se confunda con un rebote observado por nosotros.
Solo los rebotes reales afectan a tu reputación
La tasa de rebotes declarada de tu cuenta y las métricas de entregabilidad o reputación cuentan solo los rebotes con source: "delivery", es decir, los que nuestra propia canalización de envío observó en la capa SMTP. Una supresión declarada por API (source: "api") o importada (source: "import") bloquea el envío a ese identificador, pero no eleva tu tasa de rebotes declarada. Así puedes proteger la reputación de tu remitente cargando previamente direcciones que sabes que no sirven, sin contaminar la métrica que quieres proteger.
La supresión sigue a la dirección o el número
Una supresión se vincula a la dirección de email o el número de teléfono normalizado dentro del espacio de trabajo, no a un registro de contacto. Por eso, una dirección suprimida cubre a todos los contactos duplicados que la compartan. Suprime jane@example.com una vez y todos los contactos con esa dirección quedan bloqueados en email en todo el espacio de trabajo.
Referencia de reason / source
Valores de reason
reason | Familia | Creado por |
|---|---|---|
unsubscribe | Consentimiento | Enlace de baja del destinatario, POST /suppressions, POST /suppressions/import |
manual | Consentimiento | Acción de operador, POST /suppressions, POST /suppressions/import |
hard_bounce | Entregabilidad | Nuestra canalización de envío, POST /suppressions/hard-bounce |
complaint | Entregabilidad | Nuestra canalización de envío (bucles de comentarios) |
Valores de source
source | Significado | ¿Cuenta para la reputación? |
|---|---|---|
delivery | Observado por nuestra propia canalización de envío/recepción (rebote real o queja). | Sí |
api | Declarado mediante esta API REST. | No |
import | Cargado mediante POST /suppressions/import (migración masiva). | No |
unsubscribe_link (y otras fuentes de consentimiento) | Cambio de consentimiento iniciado por el destinatario. | No |
Listar supresiones
Devuelve una lista paginada de identificadores suprimidos de un canal.
Endpoint
GET /suppressions
Parámetros de consulta
| Parámetro | Tipo | Predeterminado | Descripción |
|---|---|---|---|
channel | cadena | - | email, sms o whatsapp. Obligatorio. |
reason | cadena | - | Filtro opcional: unsubscribe, hard_bounce, complaint o manual. |
limit | número | 100 | Filas por página, máximo 1000. |
offset | número | 0 | Desplazamiento de paginación. |
Solicitud de ejemplo
curl -X GET "https://api-eu1.joryio.com/suppressions?channel=email&reason=hard_bounce&limit=50" \
-H "Authorization: Bearer jry_live_your_api_key"
Respuesta
{
"items": [
{
"identifier": "dead-address@example.com",
"channel": "email",
"identifierType": "email",
"reason": "hard_bounce",
"source": "delivery",
"scope": "global",
"listId": null,
"createdAt": "2026-06-30T12:04:11.000Z"
},
{
"identifier": "jane@example.com",
"channel": "email",
"identifierType": "email",
"reason": "unsubscribe",
"source": "unsubscribe_link",
"scope": "group",
"listId": "grp_newsletter",
"createdAt": "2026-07-02T09:20:00.000Z"
}
],
"total": 214,
"limit": 50,
"offset": 0
}
Comprobar un identificador
Comprueba si un identificador concreto está suprimido en un canal.
Endpoint
GET /suppressions/{identifier}
El parámetro de ruta {identifier} es la dirección de email o el número de teléfono codificado para URL.
Parámetros de consulta
| Parámetro | Tipo | Predeterminado | Descripción |
|---|---|---|---|
channel | cadena | - | email, sms o whatsapp. Obligatorio. |
Solicitud de ejemplo
curl -X GET "https://api-eu1.joryio.com/suppressions/dead-address@example.com?channel=email" \
-H "Authorization: Bearer jry_live_your_api_key"
Respuesta: suprimido
{
"suppressed": true,
"identifier": "dead-address@example.com",
"reason": "hard_bounce",
"source": "delivery",
"scope": "global",
"listId": null,
"createdAt": "2026-06-30T12:04:11.000Z"
}
Respuesta: no suprimido
{
"suppressed": false
}
Añadir una supresión
Añade una supresión por consentimiento o manual. Úsala para respetar una baja que te haya llegado por tus propios sistemas, como un ticket de soporte, una marca del CRM o un cambio en tu propio centro de preferencias.
Endpoint
POST /suppressions
Cuerpo de la solicitud
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
channel | cadena | Sí | email, sms o whatsapp. |
identifier | cadena | Sí | Dirección de email o número de teléfono que se suprimirá. |
reason | cadena | No | manual (predeterminado) o unsubscribe. Restringido: se rechaza cualquier otro valor. |
scope | cadena | No | global (predeterminado) o group. |
listId | cadena | No | Obligatorio si scope es group: grupo/lista al que se aplica esta supresión. |
El source de una fila creada aquí siempre se registra como api. Este endpoint no puede crear un hard_bounce ni una complaint.
Solicitud de ejemplo
curl -X POST https://api-eu1.joryio.com/suppressions \
-H "Authorization: Bearer jry_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"channel": "email",
"identifier": "jane@example.com",
"reason": "unsubscribe",
"scope": "group",
"listId": "grp_newsletter"
}'
Respuesta
{
"identifier": "jane@example.com",
"channel": "email",
"identifierType": "email",
"reason": "unsubscribe",
"source": "api",
"scope": "group",
"listId": "grp_newsletter",
"createdAt": "2026-07-11T08:15:00.000Z"
}
Declarar un rebote permanente
Registra un rebote permanente de una dirección de email. Es la única ruta de API que puede declarar una supresión de entregabilidad, y está separada y restringida de forma intencionada.
Por qué este endpoint está separado
- Un rebote es normalmente algo que Joryio observa al enviar, no algo que declare quien llama. Mantener esa declaración fuera de las rutas habituales de añadir/importar evita creaciones accidentales o descuidadas.
- Como lo estás declarando tú y no observándolo nosotros, la fila lleva
source: "api". Bloquea el envío igual que un rebote real, pero nunca se confunde con uno que hayamos visto y no cuenta para tu tasa de rebotes declarada ni tus métricas de reputación de remitente. - Es solo para email. No existe equivalente para teléfono: la falta de entrega de SMS/WhatsApp se modela de otra manera.
Endpoint
POST /suppressions/hard-bounce
Cuerpo de la solicitud
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
identifier | cadena | Sí | Dirección de email que tuvo el rebote permanente. |
El canal es implícitamente email. La fila se registra con reason: "hard_bounce" y source: "api".
Solicitud de ejemplo
curl -X POST https://api-eu1.joryio.com/suppressions/hard-bounce \
-H "Authorization: Bearer jry_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"identifier": "no-such-mailbox@example.com"
}'
Respuesta
{
"identifier": "no-such-mailbox@example.com",
"channel": "email",
"identifierType": "email",
"reason": "hard_bounce",
"source": "api",
"scope": "global",
"listId": null,
"createdAt": "2026-07-11T08:20:00.000Z"
}
Importación masiva
Carga una lista de supresiones existente, por ejemplo al migrar desde otra plataforma.
Endpoint
POST /suppressions/import
Cuerpo de la solicitud
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
channel | cadena | Sí | email, sms o whatsapp. |
entries | matriz | Sí | Hasta 5000 objetos, cada uno { identifier, reason? }. |
El reason de cada entrada se restringe a manual (predeterminado) o unsubscribe; cualquier otro valor se convierte en manual. Cada fila importada se registra con source: "import". Igual que el endpoint de añadir, la importación no puede crear un rebote ni una queja.
Solicitud de ejemplo
curl -X POST https://api-eu1.joryio.com/suppressions/import \
-H "Authorization: Bearer jry_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"channel": "email",
"entries": [
{ "identifier": "old-dead-1@example.com" },
{ "identifier": "opted-out@example.com", "reason": "unsubscribe" },
{ "identifier": "old-dead-2@example.com" }
]
}'
Respuesta
{
"channel": "email",
"received": 3,
"imported": 3,
"skipped": 0,
"source": "import"
}
Eliminar una supresión (anular supresión)
Elimina una supresión para que Joryio pueda volver a enviar al identificador.
Endpoint
DELETE /suppressions/{identifier}
Parámetros de consulta
| Parámetro | Tipo | Predeterminado | Descripción |
|---|---|---|---|
channel | cadena | - | email, sms o whatsapp. Obligatorio. |
Esto elimina todas las filas de supresión del identificador en ese canal y espacio de trabajo, incluida una fila de entregabilidad hard_bounce o complaint. Es una eliminación deliberada por parte del operador o la API: anular la supresión de una dirección es precisamente cómo se borra un rebote permanente resuelto. Elimina una supresión de entregabilidad solo cuando sepas que el problema subyacente está solucionado, o correrás el riesgo de enviar a una dirección inactiva y dañar la reputación de tu remitente.
Solicitud de ejemplo
curl -X DELETE "https://api-eu1.joryio.com/suppressions/no-such-mailbox@example.com?channel=email" \
-H "Authorization: Bearer jry_live_your_api_key"
Respuesta
{
"identifier": "no-such-mailbox@example.com",
"removed": 2
}
removed es el número de filas de supresión eliminadas; un identificador puede tener a la vez una fila de consentimiento de ámbito de grupo y una fila global de entregabilidad.
Migrar una lista de supresiones existente
Cuando pases a Joryio desde otra plataforma de email o SMS, lleva tu lista de supresiones desde el primer día para que tu primer envío no vuelva a contactar direcciones que ya sabes que no sirven o que se dieron de baja.
- Importa la lista completa mediante
POST /suppressions/import. Las entradas llegan comomanual- ounsubscribesi las etiquetas así - consource: "import". Bloquean el envío y protegen la reputación de tu remitente desde el primer envío, sin aumentar tu tasa de rebotes declarada, porque las filas importadas nunca cuentan para la reputación. - Solo si necesitas específicamente que esas direcciones se informen como rebotes, por ejemplo para mantener continua la analítica de rebotes durante la migración, decláralas de una en una con
POST /suppressions/hard-bounce. Seguirán llevandosource: "api", por lo que bloquean el envío y aparecen como rebotes en la lista de supresiones sin contarse como rebotes observados por nosotros.
Para la mayoría de las migraciones, solo el paso 1 es lo correcto: detiene los envíos y mantiene limpias tus métricas de reputación.
Respuestas de error
Todos los errores comparten la estructura estándar: no existe un vocabulario separado de códigos de error legibles por máquina; usa el estado HTTP junto con el campo message. Consulta respuesta de error en el resumen de la API. Los errores de validación (400) añaden una matriz errors con un mensaje por cada campo que falla:
{
"statusCode": 400,
"message": "Bad Request Exception",
"timestamp": "2026-07-12T09:00:00.000Z",
"path": "/suppressions",
"errors": [
"reason must be one of the following values: manual, unsubscribe"
]
}
Importante: esta API aplica scopes específicos de cada canal. Una clave de API que solo tiene el scope de SMS recibe un 403 si accede a supresiones de email, y viceversa:
{
"statusCode": 403,
"message": "API key missing required scope 'email_suppression:write' for channel 'email'",
"timestamp": "2026-07-12T09:00:00.000Z",
"path": "/suppressions"
}