API HTTP de Postari

REST API para integraciones B2B · auth Bearer · respuesta JSON · webhooks HMAC-firmados para eventos email_delivered / email_opened / email_clicked / email_bounced / email_complained / email_unsubscribed.

v1 · en producción · feedback bienvenido

1 · Crea tu API key

Ve a /ajustes/seguridad y click "Crear API key". Elige el scope:

  • read · solo lectura · subscribers, stats, campañas
  • write · agregar/editar subscribers, tags, metadata
  • send · disparar envíos de campañas
  • admin · todo lo anterior + dominios + DELETE

La key se muestra UNA SOLA VEZ. Guárdala en tu vault. Formato: ef_live_xxxx

2 · Autenticación

Pasa la key como Bearer token en el header Authorization:

curl https://postari.io/api/v1/stats \
  -H "Authorization: Bearer ef_live_xxxxxxxxxxxxxxxx"

Alternativa: header x-api-key · mismo valor sin "Bearer ".

3 · Enviar campaña

POST /api/v1/campaigns/send · scope send

curl -X POST https://postari.io/api/v1/campaigns/send \
  -H "Authorization: Bearer ef_live_xxx" \
  -H "Content-Type: application/json" \
  -d '{
    "list_id": "uuid-de-tu-lista",
    "subject": "🚀 Nuevo curso disponible",
    "from_name": "Mara López",
    "from_email": "mara@coachmara.com",
    "html_body": "<h1>Hola {{first_name}}</h1><p>Tu curso ya está...</p>",
    "send_to": {
      "include_tags": ["tier:premium"],
      "exclude_tags": ["unsubscribed_promos"]
    },
    "scheduled_at": "2026-05-12T15:00:00Z"
  }'

Variables soportadas en el HTML: {{first_name}} {{from_name}} {{tenant_name}} {{unsubscribe_url}}

4 · Subscribers (CRUD)

# Agregar 1 subscriber
curl -X POST https://postari.io/api/v1/subscribers \
  -H "Authorization: Bearer ef_live_xxx" \
  -H "Content-Type: application/json" \
  -d '{
    "email": "miembro@gmail.com",
    "name": "Juan Pérez",
    "tags": ["tier:premium", "joined:2026-04"],
    "metadata": { "faroli_id": "cm456def", "ltv_cents": 29700 }
  }'

# Bulk import (max 5000 por request)
curl -X POST https://postari.io/api/v1/subscribers/bulk \
  -H "Authorization: Bearer ef_live_xxx" \
  -d '{
    "subscribers": [
      { "email": "uno@example.com", "tags": ["nuevo"] },
      { "email": "dos@example.com", "tags": ["nuevo"] }
    ],
    "on_conflict": "ignore"
  }'

# Listar paginado con cursor
curl "https://postari.io/api/v1/subscribers?limit=100&tag=tier:premium" \
  -H "Authorization: Bearer ef_live_xxx"

# Update tags
curl -X PUT https://postari.io/api/v1/subscribers/miembro%40gmail.com \
  -H "Authorization: Bearer ef_live_xxx" \
  -d '{ "tags": ["tier:premium", "completed:lesson3"] }'

# Soft delete
curl -X DELETE https://postari.io/api/v1/subscribers/miembro%40gmail.com \
  -H "Authorization: Bearer ef_live_xxx"

5 · Dominio + DKIM

Cada cuenta puede configurar 1 dominio sender. Postari devuelve los DNS records (DKIM CNAMEs + SPF + DMARC) que el creator pega en su DNS provider.

# Registrar dominio
curl -X POST https://postari.io/api/v1/domains \
  -H "Authorization: Bearer ef_live_xxx" \
  -d '{
    "domain": "coachmara.com",
    "from_email": "mara@coachmara.com",
    "from_name": "Mara López"
  }'

# Response incluye dns_records con CNAMEs DKIM, SPF y DMARC
# El creator pega esos records en Cloudflare/Hostinger/etc.

# Verificar (después de propagación DNS · típicamente 30 min - 24h)
curl -X POST "https://postari.io/api/v1/domains/coachmara.com?action=verify" \
  -H "Authorization: Bearer ef_live_xxx"

# Estado actual
curl https://postari.io/api/v1/domains/coachmara.com \
  -H "Authorization: Bearer ef_live_xxx"

6 · Webhooks de eventos

Configura un webhook en /ajustes/webhooks. Postari envía POST con HMAC-SHA256 signature en header X-Postari-Signature.

Eventos disponibles:

  • email_delivered · Resend confirma entrega
  • email_opened · pixel disparado
  • email_clicked · click en link
  • email_bounced · rebotó (hard/soft)
  • email_complained · marcó como spam
  • email_unsubscribed · usó link unsub
# Payload típico
{
  "event": "email_opened",
  "tenant_id": "uuid",
  "fired_at": "2026-05-09T20:30:00Z",
  "payload": {
    "email_id": "uuid",
    "contact_id": "uuid",
    "campaign_id": "uuid",
    "subject": "Tu asunto",
    "device_type": "mobile",
    "email_client": "apple_mail",
    "opened_at": "2026-05-09T20:30:00Z"
  }
}

# Verificar la firma en tu servidor (Node.js)
# El header es  X-Postari-Signature: t=<unix_ts>,v1=<hmac_sha256_hex>
# y lo que se firma es  `${t}.${rawBody}`  (timestamp + punto + cuerpo crudo).
const [tPart, v1Part] = req.headers['x-postari-signature'].split(',');
const t  = tPart.slice(2);   // quita "t="
const v1 = v1Part.slice(3);  // quita "v1="

const expected = crypto
  .createHmac('sha256', WEBHOOK_SECRET)
  .update(`${t}.${rawBody}`)
  .digest('hex');

// Comparación en tiempo constante · no uses !==
const ok = crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(v1));
if (!ok) return res.status(401).end();

// Y rechaza lo viejo: sin esto, quien capture un webhook puede reenviarlo siempre.
if (Math.abs(Date.now() / 1000 - Number(t)) > 300) return res.status(401).end();

7 · Stats y analytics

# Resumen del período
curl "https://postari.io/api/v1/stats?from=2026-04-01&to=2026-05-01" \
  -H "Authorization: Bearer ef_live_xxx"

# Stats por campaña (incluye by_link[])
curl https://postari.io/api/v1/campaigns/uuid-campaña/stats \
  -H "Authorization: Bearer ef_live_xxx"

by_link[]: cada URL clickeada con clicks totales y unique_clicks (1 por contact).

8 · Códigos de error

CódigoCuándo
400Body inválido o campos requeridos faltantes
401API key inválida, expirada o revocada
403API key sin scope suficiente para este endpoint
404Recurso (subscriber, campaña, dominio) no encontrado
409Conflicto · subscriber ya existe, dominio ya configurado
422Validation error · ej. dominio no verificado al intentar enviar
423Cuenta con envíos congelados (sending_frozen)
429Rate limit excedido · header Retry-After indica cuándo reintentar
502Error con provider externo (Resend, etc.)
500Error interno · contacta soporte

9 · Rate limits

  • · 100 req/min por API key (subible para clientes enterprise)
  • · 5000 subscribers max por request bulk (chunkear si tienes más)
  • · Send recipients según plan del tenant: 25K (Creator) · 100K (Pro) · 300K (Business) · ilimitado (Enterprise)
  • · Webhook timeout: 10 segundos · si tu endpoint no responde, reintentamos 3 veces con exponential backoff

¿Dudas o reportar bug? Email hi@postari.io

Postari API v1 · base URL https://postari.io/api/v1