SendyPOPGuía técnica de la API · API v1 · Octubre 2026 DocumentaciónReferencia interactivaDescargar PDF

Integraciones

API de SendyPOP

Conectá tu CRM, tienda o sistema propio con SendyPOP: envío transaccional, contactos y grupos, campañas, automatizaciones disparadas por eventos, avisos en tiempo real por webhooks y reportes.

DatoValor
URL basehttps://sendypop.com/api (todas las rutas empiezan con /v1)
FormatoJSON en UTF-8 (Content-Type: application/json)
AutenticaciónAuthorization: Bearer <API key> o X-API-Key: <API key>
Referencia completahttps://sendypop.com/api/docs (OpenAPI, se puede importar en Postman)

1Alta de la conexión

Cada API key pertenece a una sola empresa y sólo opera sobre sus datos. La crea el equipo de Soporte en Configuración de API o, si la empresa tiene la autogestión habilitada, su administrador desde API en el panel. Para cada integración:

  1. Una clave por integración y ambiente (por ejemplo tienda-produccion y tienda-pruebas). Así se puede revocar una sin cortar las demás. Las claves de Pruebas (cmpk_test_…) no envían emails reales: ver Modo prueba.
  2. Permisos mínimos. Elegí sólo lo que la integración usa (tabla abajo).
  3. IPs permitidas. Si el sistema que llama tiene IPs fijas, cargalas (IP o rango CIDR, IPv4 o IPv6). Un pedido desde otra dirección se rechaza con 403 ip_not_allowed. Sin lista, la clave funciona desde cualquier IP.
  4. El secreto se muestra una sola vez, al crearla. Guardalo en el gestor de secretos de tu sistema; nunca en el código, tickets ni correos. Si se pierde o se filtra: revocar y crear otra.
  5. Para recibir avisos de entregas, rebotes, aperturas o bajas, configurá un webhook.
PermisoPermite
messages:send · messages:readEnviar emails transaccionales · consultar su estado
contacts:read · contacts:writeVer · crear, editar, importar y eliminar contactos, grupos y etiquetas
campaigns:read · campaigns:write · campaigns:sendVer · crear y editar · enviar y programar campañas
automations:read · automations:writeVer · crear, activar y pausar automatizaciones
events:read · events:writeConsultar · registrar eventos que disparan automatizaciones
webhooks:read · webhooks:writeVer · administrar webhooks y sus entregas
reports:read · reports:exportGenerar · exportar reportes (Excel, CSV o PDF), guardarlos y programar envíos
domains:read · domains:writeVer · agregar y verificar dominios

2Autenticación, IPs permitidas y límites

curl https://sendypop.com/api/v1/lists \
  -H "Authorization: Bearer cmpk_live_xxxxxxxxxxxxxxxx"

3Respuestas y errores

Los errores devuelven JSON con un código estable y un mensaje legible: {"error":"codigo","message":"…"}.

HTTPSignificadoQué hacer
200 / 201 / 202OK · creado · aceptado (se procesa en segundo plano)—
400Datos inválidos (invalid_body, con details por campo)Corregir el pedido; no reintentar igual
401Falta la clave o no es válida (unauthorized, invalid_api_key)Revisar la clave y sus permisos
403IP no permitida (ip_not_allowed), otra empresa o falta de verificación (por ejemplo sender_domain_not_verified)Ver el mensaje; no reintentar sin cambios
404Recurso inexistente en esta empresa—
409Estado incompatible (por ejemplo una campaña ya enviada, o un bloqueo anti-spam). idempotency_request_in_progress: el pedido original con esa Idempotency-Key todavía se procesaRevisar el estado del recurso · reintentar en unos segundos con la misma clave
422idempotency_key_reused: la misma Idempotency-Key se usó con otro contenidoUsar una clave nueva por cada envío distinto
429Límite de pedidos o cupo de envíoReintentar después de Retry-After
5xxError temporalReintentar con espera exponencial

4Envío transaccional

Para emails individuales disparados por tu sistema (confirmaciones, facturas, recuperos). El remitente debe ser un remitente activo de un dominio verificado de la empresa.

POST /v1/messages            permiso messages:send
{
  "from": "novedades@tuempresa.com",
  "to": "cliente@ejemplo.com",
  "subject": "Tu pedido 1234 fue confirmado",
  "html": "<p>Hola Ana, tu pedido está en camino.</p>",
  "text": "Hola Ana, tu pedido está en camino.",
  "tags": { "pedido": "1234" }
}

202 Accepted
{ "messageId": "6f1c…", "status": "queued", "tenantId": "a7b3…", "reputation": { … } }

Reintentos sin duplicados: Idempotency-Key

Si tu sistema reintenta un envío por un corte de red o un timeout, enviá la cabecera Idempotency-Key con un valor único por email (por ejemplo el número de pedido). SendyPOP procesa el primer pedido y, ante un reintento con la misma clave y el mismo contenido, devuelve la misma respuesta sin crear otro mensaje.

curl -X POST https://sendypop.com/api/v1/messages \
  -H "Authorization: Bearer cmpk_live_xxxxxxxxxxxxxxxx" \
  -H "Idempotency-Key: pedido-1234-confirmacion" \
  -H "Content-Type: application/json" \
  -d '{"from":"novedades@tuempresa.com","to":"cliente@ejemplo.com","subject":"Tu pedido 1234","text":"…"}'

Modo prueba

Las claves creadas con ambiente Pruebas sirven para integrar sin enviar emails reales. Validan todo igual que producción (clave, permisos, IPs, dominio verificado y remitente activo), pero la entrega se simula: no se envía ningún email, no se consume cupo y el resultado llega a tus webhooks con "sandbox": true en data.

202 Accepted
{ "messageId": "9b2e…", "status": "simulated", "outcome": "delivered", "sandbox": true, "webhookDeliveries": 1 }
DestinatarioResultado simuladoWebhook
cualquier direcciónentregadomessage.delivered
termina en +bounce (por ejemplo ana+bounce@ejemplo.com)rebotemessage.bounced
termina en +complaintquejamessage.complained

GET /v1/messages/{messageId} y /events también responden para los mensajes simulados. Para pasar a producción, creá una clave de ambiente Producción: no hace falta cambiar nada más.

5Contactos, grupos y etiquetas

POST /v1/contacts                    contacts:write
{ "email": "ana@ejemplo.com", "firstName": "Ana", "lastName": "Pérez",
  "listId": "<id del grupo>", "attrs": { "ciudad": "Rosario" } }

POST /v1/contacts/import-batch       contacts:write   (hasta 5.000 por pedido)
{ "listId": "<id del grupo>", "contacts": [ { "email": "a@ejemplo.com", "firstName": "A" }, … ] }

POST /v1/contacts/lookup             contacts:read    (hasta 500 emails)
{ "emails": ["ana@ejemplo.com"] }
OperaciónRuta
Grupos: listar · crear · renombrar · eliminarGET/POST /v1/lists · PATCH/DELETE /v1/lists/{listId}
Miembros de un grupoGET/POST /v1/lists/{listId}/contacts · POST /v1/lists/{listId}/memberships
Editar · eliminar un contactoPATCH/DELETE /v1/contacts/{contactId}
Grupos y etiquetas de un contactoPUT /v1/contacts/{contactId}/lists · PUT /v1/contacts/{contactId}/tags
EtiquetasGET/POST /v1/tags · PATCH/DELETE /v1/tags/{tagId} · POST /v1/contacts/bulk-tags

Las eliminaciones masivas (por ejemplo un grupo grande) se aceptan de inmediato y la limpieza física sigue en segundo plano.

6Campañas

POST /v1/campaigns                   campaigns:write
{ "name": "Novedades octubre", "subject": "Lo nuevo de octubre",
  "senderEmail": "novedades@tuempresa.com", "listIds": ["<id del grupo>"],
  "contentHtml": "<h1>Hola {{nombre}}</h1>…" }

POST /v1/campaigns/{campaignId}/send       campaigns:send
POST /v1/campaigns/{campaignId}/schedule   campaigns:send
{ "scheduledAt": "2026-11-02T13:00:00Z" }

7Eventos y automatizaciones

Registrá lo que pasa en tu sistema (una compra, un alta) y SendyPOP dispara las automatizaciones cuyo disparador es Evento recibido por API con ese nombre.

POST /v1/events                      events:write
{ "email": "ana@ejemplo.com", "name": "compra_confirmada",
  "properties": { "pedido": "1234", "total": 15990 },
  "idempotencyKey": "pedido-1234" }

8Webhooks

SendyPOP avisa a tu sistema, con un POST firmado, cada evento elegido. Se configuran desde Soporte o el panel (Configuración de API) o por API (POST /v1/webhooks, permiso webhooks:write).

EventoCuándo
message.deliveredEl servidor de destino aceptó el mensaje
message.deferredDemora temporal; SendyPOP reintenta
message.bouncedRebote definitivo (incluye reason, smtpCode)
message.failedNo se pudo entregar (vencido o rechazado)
message.complainedEl destinatario lo marcó como spam
message.opened · message.clickedApertura · clic (incluye url)
contact.unsubscribedEl destinatario se dio de baja
webhook.testPrueba enviada con el botón Probar
POST https://tu-sistema.com/webhooks/sendypop
Content-Type: application/json
SendyPOP-Event: message.bounced
SendyPOP-Delivery: 3c9e…            (id de la entrega)
SendyPOP-Signature: t=1792610000,v1=5f2a…

{ "id": "b81d…", "type": "message.bounced", "createdAt": "2026-10-21T18:20:01.000Z",
  "tenantId": "a7b3…",
  "data": { "messageId": "6f1c…", "email": "cliente@ejemplo.com", "campaignId": null,
            "subject": "Tu pedido 1234", "tags": { "pedido": "1234" },
            "occurredAt": "2026-10-21T18:20:01.000Z",
            "reason": "550 5.1.1 user unknown", "smtpCode": 550 } }

Verificar la firma

Calculá un HMAC-SHA256 con el secreto del webhook sobre <t>.<cuerpo exacto recibido> y compará en tiempo constante con v1. Rechazá firmas con más de 5 minutos de antigüedad.

// Node.js
import { createHmac, timingSafeEqual } from "node:crypto";
function validSendyPopSignature(rawBody, header, secret) {
  const parts = Object.fromEntries(header.split(",").map((p) => p.split("=")));
  if (Math.abs(Date.now() / 1000 - Number(parts.t)) > 300) return false;
  const expected = createHmac("sha256", secret).update(`${parts.t}.${rawBody}`).digest("hex");
  return timingSafeEqual(Buffer.from(expected), Buffer.from(parts.v1 ?? ""));
}
# Python
import hmac, hashlib, time
def valid_sendypop_signature(raw_body: bytes, header: str, secret: str) -> bool:
    parts = dict(p.split("=", 1) for p in header.split(","))
    if abs(time.time() - int(parts["t"])) > 300: return False
    expected = hmac.new(secret.encode(), f"{parts['t']}.".encode() + raw_body, hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, parts.get("v1", ""))
// PHP
function valid_sendypop_signature(string $rawBody, string $header, string $secret): bool {
  parse_str(str_replace(',', '&', $header), $parts);
  if (abs(time() - (int)$parts['t']) > 300) return false;
  $expected = hash_hmac('sha256', $parts['t'] . '.' . $rawBody, $secret);
  return hash_equals($expected, $parts['v1'] ?? '');
}

Reintentos y buenas prácticas

9Reportes y dominios

10Monitoreo de la conexión

En Configuración de API (Soporte) y en API (panel de la empresa) se ve, por clave y por hora de las últimas 48 horas:

Toda alta, cambio de IPs o permisos, revocación y cambio de webhook queda en la auditoría con quién lo hizo y cuándo.

11Checklist de puesta en producción

  1. Dominio verificado (SPF, DKIM, DMARC y tracking) y remitente activo.
  2. Clave de producción con permisos mínimos y, si es posible, IPs permitidas.
  3. Secreto guardado en un gestor de secretos; nunca en el repositorio.
  4. Manejo de 429 con Retry-After y reintentos exponenciales para 5xx.
  5. Integración probada de punta a punta con una clave de modo prueba, incluidos rebotes y quejas simulados.
  6. Cabecera Idempotency-Key en cada envío; idempotencyKey en eventos; deduplicación por id en webhooks.
  7. Webhook probado con el botón Probar y firma validada.
  8. Prueba real a casillas propias y revisión del monitoreo después de la primera hora.
Soporte técnico: info@sendypop.comSendyPOP · Guía técnica de la API v1