Zeabur EmailReferencia de API REST

Referencia de REST API

Zeabur Email proporciona una API REST completa que facilita la integración de funcionalidad de envío de correos en su aplicación.

Autenticación

Todas las solicitudes API deben incluir una clave API (formato Bearer Token) en el encabezado HTTP:

Authorization: Bearer zs_your_api_key_here

Las claves API se pueden crear y gestionar en la página de gestión de Zeabur Email de la consola de Zeabur.

URL Base

https://api.zeabur.com/api/v1/zsend

Envío de Correos

Enviar Correo Individual

Enviar un correo inmediatamente.

POST /emails

Cuerpo de la Solicitud

{
  "from": "[email protected]",
  "to": ["[email protected]"],
  "cc": ["[email protected]"],           // Opcional
  "bcc": ["[email protected]"],         // Opcional
  "reply_to": ["[email protected]"], // Opcional
  "subject": "Asunto del Correo",
  "html": "<h1>Contenido HTML</h1>",
  "text": "Contenido de texto plano",
  "attachments": [                    // Opcional
    {
      "filename": "document.pdf",
      "content": "base64_encoded_content",
      "content_type": "application/pdf"
    }
  ],
  "headers": {                        // Opcional
    "X-Custom-Header": "value"
  },
  "tags": {                           // Opcional
    "campaign": "newsletter",
    "user_id": "12345"
  }
}

Descripción de Campos

CampoTipoRequeridoDescripción
fromstringDirección de correo del remitente, el dominio debe estar verificado
toarrayLista de direcciones de correo de destinatarios
ccarrayNoLista de direcciones de correo CC
bccarrayNoLista de direcciones de correo BCC
reply_toarrayNoLista de direcciones de respuesta
subjectstringAsunto del correo (máximo 998 caracteres)
htmlstringNo*Contenido del correo en formato HTML (máximo 5 MB)
textstringNo*Contenido del correo en texto plano (máximo 5 MB)
attachmentsarrayNoLista de archivos adjuntos (máximo 10, cada uno hasta 10 MB)
headersobjectNoEncabezados de correo personalizados (máximo 50)
tagsobjectNoEtiquetas personalizadas para categorización y seguimiento
⚠️

Debe proporcionarse al menos uno de html o text. Si se proporcionan ambos, los clientes de correo priorizarán la versión HTML, mientras que los clientes que no soporten HTML mostrarán la versión de texto plano. El total de destinatarios (to + cc + bcc) no puede exceder 50.

Respuesta

{
  "id": "696de2c84210d814d66ee052",
  "message_id": "",
  "status": "pending"
}

Ejemplo

curl -X POST https://api.zeabur.com/api/v1/zsend/emails \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -d '{
    "from": "[email protected]",
    "to": ["[email protected]"],
    "subject": "Bienvenido a Zeabur Email",
    "html": "<h1>¡Bienvenido!</h1><p>Gracias por usar Zeabur Email.</p>"
  }'

Enviar Correo con Archivos Adjuntos

El contenido de los archivos adjuntos debe codificarse en Base64:

// Ejemplo de JavaScript
const fs = require('fs');
 
const fileContent = fs.readFileSync('document.pdf');
const base64Content = fileContent.toString('base64');
 
const response = await fetch('https://api.zeabur.com/api/v1/zsend/emails', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Authorization': 'Bearer YOUR_API_KEY'
  },
  body: JSON.stringify({
    from: '[email protected]',
    to: ['[email protected]'],
    subject: 'Prueba de Archivo Adjunto',
    html: '<p>Por favor vea el archivo adjunto</p>',
    attachments: [{
      filename: 'document.pdf',
      content: base64Content,
      content_type: 'application/pdf'
    }]
  })
});

Envío Programado

Programar Correo

Programar un correo para ser enviado en un momento específico.

POST /emails/schedule

Cuerpo de la Solicitud

Igual que el envío de correo individual, con un campo adicional scheduled_at:

{
  "from": "[email protected]",
  "to": ["[email protected]"],
  "cc": ["[email protected]"],              // Opcional
  "bcc": ["[email protected]"],            // Opcional
  "reply_to": ["[email protected]"],  // Opcional
  "subject": "Correo Programado",
  "html": "<h1>Contenido HTML</h1>",
  "text": "Contenido de texto plano",
  "attachments": [],                     // Opcional
  "headers": {},                         // Opcional
  "tags": {},                            // Opcional
  "scheduled_at": "2026-01-25T10:00:00Z" // Requerido, formato ISO 8601
}

La hora de scheduled_at debe ser en el futuro. Todos los demás campos siguen las mismas reglas que el envío de correo individual.

Respuesta

{
  "id": "696de2c84210d814d66ee053",
  "status": "enqueued"
}

Listar Correos Programados

GET /emails/scheduled

Parámetros de Consulta

ParámetroTipoDescripción
pagenumberNúmero de página (predeterminado 1)
limitnumberElementos por página (predeterminado 20, máximo 100)
statusstringFiltrar por estado: scheduled, sent, cancelled

Respuesta

{
  "scheduled_emails": [
    {
      "id": "696de2c84210d814d66ee053",
      "from": "[email protected]",
      "to": ["[email protected]"],
      "subject": "Correo Programado",
      "scheduled_at": "2026-01-25T10:00:00Z",
      "status": "enqueued",
      "created_at": "2026-01-20T08:00:00Z",
      "attempts": 0
    }
  ],
  "total_count": 1
}

Obtener Detalles de Correo Programado

GET /emails/scheduled/:id

Cancelar Correo Programado

DELETE /emails/scheduled/:id

Respuesta

{
  "success": true,
  "message": "Scheduled email cancelled"
}

Envío por Lotes

Enviar Correos por Lotes

Enviar una gran cantidad de correos a la vez, con cada correo teniendo diferentes destinatarios y contenido.

POST /emails/batch

Cuerpo de la Solicitud

{
  "emails": [
    {
      "from": "[email protected]",
      "to": ["[email protected]"],
      "cc": ["[email protected]"],       // Opcional
      "bcc": ["[email protected]"],      // Opcional
      "reply_to": ["[email protected]"], // Opcional
      "subject": "Correo Personalizado 1",
      "html": "<p>¡Hola, Usuario 1!</p>",
      "text": "¡Hola, Usuario 1!",         // Opcional
      "attachments": [],                   // Opcional
      "headers": {},                       // Opcional
      "tags": {"user_id": "1"}             // Opcional
    },
    {
      "from": "[email protected]",
      "to": ["[email protected]"],
      "subject": "Correo Personalizado 2",
      "html": "<p>¡Hola, Usuario 2!</p>"
    }
    // ... hasta 100 correos
  ]
}

Un envío por lotes admite hasta 100 correos. Cada correo admite todos los mismos campos que el envío de correo individual, incluyendo cc, bcc, reply_to, attachments, headers y tags.

Respuesta

{
  "job_id": "696de2c84210d814d66ee054",
  "status": "pending",
  "total_count": 2
}

Descripción de Campos

CampoTipoDescripción
job_idstringID del trabajo por lotes para consultar el estado y detalles más tarde
statusstringEstado inicial del trabajo (generalmente pending)
total_countnumberNúmero total de correos en el trabajo por lotes

job_id es el identificador único del trabajo por lotes, diferente del id del correo individual. Guarde este job_id para consultar el progreso y los resultados del envío por lotes más tarde.

Listar Trabajos por Lotes

GET /emails/batch

Parámetros de Consulta

Iguales que la lista de correos programados.

Obtener Detalles del Trabajo por Lotes

GET /emails/batch/:id

Respuesta

{
  "job_id": "696de2c84210d814d66ee054",
  "total_count": 100,
  "sent_count": 95,
  "failed_count": 5,
  "status": "completed",
  "created_at": "2026-01-20T08:00:00Z",
  "completed_at": "2026-01-20T08:15:00Z"
}

Consultas de Correos

Listar Correos

GET /emails

Parámetros de Consulta

ParámetroTipoDescripción
pagenumberNúmero de página (predeterminado 1)
page_sizenumberElementos por página (predeterminado 20, máximo 100)
statusstringFiltrar por estado: pending, sent, delivered, bounced, complained

Respuesta

{
  "data": [
    {
      "id": "696de2c84210d814d66ee052",
      "from": "[email protected]",
      "to": ["[email protected]"],
      "subject": "Correo de Prueba",
      "status": "delivered",
      "created_at": "2026-01-20T08:00:00Z"
    }
  ],
  "total": 1
}

Obtener Detalles del Correo

GET /emails/:id

Respuesta

{
  "id": "696de2c84210d814d66ee052",
  "message_id": "0111019bd53de187-bda14a71-25a3-4fdc-a1a0-f543ff58c085-000000",
  "from": "[email protected]",
  "to": ["[email protected]"],
  "cc": [],
  "bcc": [],
  "reply_to": [],
  "subject": "Correo de Prueba",
  "html": "<h1>Prueba</h1>",
  "text": "Prueba",
  "status": "delivered",
  "mal_status": "healthy",
  "created_at": "2026-01-20T08:00:00Z",
  "headers": {},
  "tags": {},
  "attachments": []
}

Manejo de Errores

La API utiliza códigos de estado HTTP estándar:

Código de EstadoDescripción
200Solicitud exitosa
400Parámetros de solicitud incorrectos
401No autorizado (clave API inválida o faltante)
403Prohibido (permisos insuficientes o cuenta suspendida)
404Recurso no encontrado
429Demasiadas solicitudes (limitado por tasa)
500Error interno del servidor

Formato de Respuesta de Error

{
  "error": "Descripción breve del error",
  "message": "Mensaje de error detallado"
}

Ejemplos de Errores Comunes

Error de Validación (400)

{
  "error": "validation error",
  "message": "subject length (1200) exceeds maximum (998 characters)"
}

Error de Autenticación (401)

{
  "error": "unauthorized",
  "message": "Invalid or missing API key"
}

Error de Permiso (403)

{
  "error": "permission denied",
  "message": "API key does not have permission to send from this domain"
}

Error de Cuota Excedida (429)

{
  "error": "daily quota exceeded (55/55), resets at 2026-01-23 00:00:00"
}

Límites

Límite de Cuota Diaria

Cada cuenta de usuario tiene una cuota de envío diaria (Daily Quota), que es el límite más importante:

Nivel de CuentaCuota Diaria PredeterminadaDescripción
Usuario Nuevo100 correos/díaCuota inicial después de la creación de la cuenta
Verificado1,000 correos/díaAumenta automáticamente después de la verificación del dominio

Tiempo de Reinicio de Cuota: Se reinicia automáticamente diariamente a las UTC 00:00

Cuando se Excede la Cuota:

  • Devuelve código de estado: 429 Too Many Requests
  • Mensaje de error: daily quota exceeded (actual/total), resets at time
  • Operaciones de lectura aún disponibles: Puede continuar consultando el historial y detalles de correos
  • Operaciones de envío rechazadas: Incluye envíos individuales, programados y por lotes

Límites de Contenido

  • Cantidad de destinatarios: Máximo 50 destinatarios por correo (to + cc + bcc)
  • Tamaño del correo: Tamaño total máximo 10 MB (incluidos archivos adjuntos y encabezados)
  • Cantidad de archivos adjuntos: Máximo 10 archivos adjuntos
  • Tamaño de archivo adjunto individual: Máximo 10 MB
  • Longitud del asunto: Máximo 998 caracteres
  • Contenido HTML: Máximo 5 MB
  • Contenido de texto: Máximo 5 MB
  • Envío por lotes: Máximo 100 correos por lote

Límites de Estado de Usuario

El estado de la cuenta de usuario afecta el acceso a la API:

EstadoAcceso APIEnviar CorreoConsultar CorreoDescripción
healthyEstado normal, puede enviar correos
reviewEn revisión, aún puede enviar (la cuota puede reducirse)
paused❌ (403)Suspendido, puede consultar pero no puede enviar
banned❌ (401)Prohibido, completamente prohibido acceder a la API

Razones de Suspensión/Prohibición de Cuenta:

  • Tasa de Rebote ≥ 4.0%
  • Tasa de Quejas ≥ 0.08%
  • Violación de términos de servicio

Descripciones de Estado:

  • review (En Revisión): Problemas de calidad de correo detectados, el sistema marca automáticamente para revisión. Si no hay comportamiento malicioso adicional dentro de 24 horas, puede recuperarse automáticamente al estado healthy.
  • paused (Suspendido): Temporalmente prohibido enviar, pero aún puede consultar datos históricos, gestionar dominios, etc. Necesita contactar al equipo de soporte para apelar, la recuperación más rápida es 24 horas después de la aprobación.
  • banned (Prohibido): Completamente prohibido acceder a la API, incluidas las operaciones de consulta. Este estado es establecido manualmente por el personal, indicando violaciones graves, y generalmente no es recuperable.
⚠️

Las solicitudes que excedan los límites devolverán un error 400 Bad Request. La cuota excedida devuelve 429 Too Many Requests.


Mejores Prácticas

1. Reintento de Errores

Para errores temporales (como 500 o 429), se recomienda usar reintento con retroceso exponencial:

async function sendEmailWithRetry(emailData, maxRetries = 3) {
  for (let i = 0; i < maxRetries; i++) {
    try {
      const response = await fetch('https://api.zeabur.com/api/v1/zsend/emails', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'Authorization': 'Bearer YOUR_API_KEY'
        },
        body: JSON.stringify(emailData)
      });
      
      if (response.ok) {
        return await response.json();
      }
      
      if (response.status === 400 || response.status === 403) {
        // Errores del cliente, no reintentar
        throw new Error(await response.text());
      }
      
      // Otros errores, reintentar después de esperar
      if (i < maxRetries - 1) {
        await new Promise(resolve => setTimeout(resolve, Math.pow(2, i) * 1000));
      }
    } catch (error) {
      if (i === maxRetries - 1) throw error;
    }
  }
}

2. Usar Envío por Lotes

Al enviar múltiples correos, use la interfaz de envío por lotes en lugar de llamar en bucle al envío individual:

// ✅ Recomendado
await fetch('https://api.zeabur.com/api/v1/zsend/emails/batch', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Authorization': 'Bearer YOUR_API_KEY'
  },
  body: JSON.stringify({
    emails: users.map(user => ({
      from: '[email protected]',
      to: [user.email],
      subject: `Hola, ${user.name}`,
      html: `<p>Contenido personalizado</p>`
    }))
  })
});
 
// ❌ No recomendado
for (const user of users) {
  await fetch('https://api.zeabur.com/api/v1/zsend/emails', {
    // ... envío individual
  });
}

3. Usar Webhooks

Configure Webhooks para recibir actualizaciones de estado de correo en tiempo real en lugar de sondear la interfaz de consulta. Consulte Configuración de Webhooks para más detalles.

4. Usar Etiquetas Apropiadamente

Use el campo tags para marcar correos para facilitar el seguimiento y análisis:

{
  "tags": {
    "campaign": "welcome_series",
    "user_segment": "new_users",
    "template_version": "v2"
  }
}