Referencia de la API pública
Para desarrolladores
Documentación de la API pública de Fidelizador. Está dirigida a desarrolladores que integran su sistema con la plataforma para enviar correo, consultar su estado y actividad, gestionar dominios y remitentes, y recibir webhooks.
Base URL y versionado
- Base URL producción:
https://cl2api.fidelizador.com - Base URL sandbox: comparte el mismo host de producción y se activa por el dominio del destinatario, ver Validar su integración en sandbox.
- Versión: se indica en el path (
/v1/..., sin prefijo/api) y es por endpoint. Si un cambio en un endpoint haría fallar las integraciones existentes, ese endpoint pasa a la versión siguiente y los demás conservan la suya. Por eso pueden convivir/v2/mails/sendy/v1/mails. Una integración solo migra los endpoints que cambiaron. La versión vigente de cada endpoint está en su ficha. - Formato: JSON en el request y en la respuesta, con el header
Content-Type: application/json. - Alcance del host: expone la API pública (
/v1/..., autenticada por API key). Las credenciales y la configuración de la instancia se gestionan desde el panel, no por la API; la única excepción son los webhooks, que sí se gestionan por la API (ver Webhooks).
Autenticación
La API se autentica con una API key:
- Header:
Authorization: Bearer <API_KEY>. - Header adicional obligatorio:
X-Instance-Slug: <slug>. - Gestión: desde el panel. Las API keys se crean, listan y revocan ahí; no hay endpoint de gestión en este host.
Endpoints principales
Cada endpoint tiene su ficha, con request y response tipados, parámetros de query y errores. La tabla las enlaza por familia.
| Familia | Endpoints |
|---|---|
/v1/mails | send · list · get · logs |
/v1/activities | sent · sent/export · bounced · bounced/export · opens · opens/export · unopened · unopened/export · clicks · clicks/export |
/v1/stats | overview |
/v1/domains/v1/senders | Gestión de dominios (DKIM, SPF) y remitentes (ver Dominios y remitentes). |
/v1/mail-templates | list · get · create · update · format · format module · validate · preview · html-import. El diseño se envía completo en config (recorrido); publicar, despublicar y eliminar se hacen desde el panel |
/v1/template-catalog | list · get: solo lectura |
/v1/mail-restrictions | list: solo lectura |
/v1/mail-unsubscribes | list · get |
/v1/mail-complaints | list · get |
/v1/fields/v1/datasets/v1/lists/v1/forms/v1/consent-terms/v1/consent-purposes/v1/consent-events/v1/consent-rules | Catálogo de campos, datasets, listas, formularios (incluido el registro de un envío de formulario) y consentimiento (Ley 21.719). Ver Campos, formularios y consentimiento. |
/v1/webhooks | list · get · create · update · delete · rotate-secret · test |
La propia API publica su contrato OpenAPI vigente: la referencia navegable está en https://$API_HOST/docs y el spec en https://$API_HOST/openapi.json, que se puede importar en Postman o Insomnia. Ante una diferencia con esta guía, rige el contrato OpenAPI. GET https://$API_HOST/ devuelve un documento con esos enlaces y el de esta guía.
Ejemplos
Los ejemplos usan tres variables. Expórtelas una vez y podrá copiar cada comando tal cual:
$API_HOST— el host de la Base URL.$API_KEY— su API key, tal como la muestra el panel.$SLUG— el identificador de su instancia, el que muestra el selector Instancia del panel.
export API_HOST=cl2api.fidelizador.com
export API_KEY=<su-api-key>
export SLUG=<su-slug>
El ejemplo curl completo de cada endpoint está en su ficha, enlazada desde la tabla de Endpoints principales.
Enviar un correo (POST /v1/mails/send, ver ficha completa):
curl -X POST "https://$API_HOST/v1/mails/send" \
-H "Authorization: Bearer $API_KEY" \
-H "X-Instance-Slug: $SLUG" \
-H "Content-Type: application/json" \
-d '{
"sender_email": "[email protected]",
"to": [{ "email": "[email protected]", "name": "Destinatario" }],
"subject": "Bienvenido",
"html": "<p>Hola, gracias por registrarte.</p>"
}'
Identificadores
Estos son los identificadores que aparecen en las respuestas y en los logs:
| ID | Origen | Dónde aparece |
|---|---|---|
request_id | Lo genera la API en cada request HTTP | Header X-Request-Id de la respuesta, logs, mensaje de error |
msg_id | Lo devuelve POST /v1/mails/send al encolar el correo | En la respuesta de POST /v1/mails/send, como message_id. En GET /v1/mails y en los logs de entrega, como msg_id. |
mail_id | Uno por destinatario del envío | Reportes, payloads de webhook |
Webhooks
Un webhook entrega a un endpoint HTTPS propio los eventos de los correos a medida que ocurren. Se gestionan con los endpoints de /v1/webhooks (scopes webhooks:read y webhooks:write); el formato de las entregas, la verificación de la firma y los reintentos están en Webhooks.
Sandbox
El sandbox es un entorno de pruebas con dominios y prefijos que simulan situaciones reales de entrega. Ver Validar su integración en sandbox.
Filtros de texto
Los filtros de texto de los listados (domain, name, email, subject, recipient) tienen dos
modos de coincidencia. Cada ficha declara cuál usa su filtro:
| Modo | Qué hace | Dónde |
|---|---|---|
| Parcial | Coincide si el valor aparece en cualquier parte del campo, sin distinguir mayúsculas. | domain, name, email, subject, y recipient en los listados de restricciones, desuscripciones y quejas |
| Exacta | Coincide solo con la dirección completa. | recipient en el listado de correos y en los de actividad; estos últimos aceptan además recipient_operator=starts_with, que lo cambia a prefijo |
El filtro recipient de esos tres listados usa coincidencia parcial: así se puede consultar por
dominio, como [email protected] para listar todo lo restringido de ese dominio. La contrapartida es
que [email protected] también devuelve a [email protected], porque la primera
dirección está contenida en la segunda. Para saber si una dirección puntual está restringida, compare
la dirección de cada resultado: no basta con que la respuesta traiga registros.
Los caracteres % y _ se buscan literales. La API los escapa, así que no funcionan como
comodines: un ?name=50%25 (es decir, 50%) devuelve las plantillas cuyo nombre contiene el texto
50%, y no las que tienen un 50 seguido de cualquier cosa. No hay búsqueda con comodines.
Una dirección con + debe ir codificada como %2B. En una query string el + se
decodifica como espacio, así que enviarlo tal cual busca usuario [email protected] y la respuesta
es un 200 con la lista vacía. La búsqueda falla en silencio, sin un error que lo indique:
# correcto
curl "https://$API_HOST/v1/mail-unsubscribes?recipient=usuario%[email protected]" \
-H "Authorization: Bearer $API_KEY" -H "X-Instance-Slug: $SLUG"
# incorrecto - el `+` llega como espacio y no coincide con nada
curl "https://$API_HOST/v1/[email protected]" ...
La regla general es codificar todo valor de query string; el + es el caso que más sorprende
porque el resto de una dirección de correo viaja sin cambios.
Formato de respuesta
En una respuesta exitosa, el body tiene una de dos formas:
- Recurso individual: sus campos van en el nivel superior, no dentro de
data. - Colección:
{ "data": [...], "pagination": {...} }, paginada conpageypage_size.
Los códigos HTTP siguen RFC 9110:
200: respuesta con body.201: recurso creado; incluye el headerLocation.204: respuesta sin body.
El formato completo, la paginación y los headers (X-Request-Id, X-Trace-Id, Location) se describen en Paginación y formato de respuesta.
Errores comunes
Los errores se devuelven en formato RFC 9457 application/problem+json. Use code para distinguir un error de otro en su código: es el identificador del error y no cambia. El formato del body, el detalle por campo (errors[], con code, pointer y params) y la lista de códigos están en Respuestas de error.
Resumen de códigos HTTP:
| Código | Uso |
|---|---|
| 200 / 201 | Operación exitosa |
| 400 | Request mal formado |
| 401 | No autenticado |
| 403 | Autenticado pero sin permisos |
| 404 | El recurso no existe |
| 409 | Conflicto (p. ej. recurso ya existe) |
| 422 | Validación fallida: incluye errors[] con code/pointer por campo |
| 429 | Límite de ancho de banda de la instancia excedido; incluye el header Retry-After |
| 500 | Error interno. Repórtelo con el trace_id del body de la respuesta |