ESEN

API v1

Base URL: https://zend24.com/api/v1 · Auth: Authorization: Bearer sk_live_...

POST /emails

Envía un email. Campos: from, to (string o array, máx 50), subject, y html, text o template + variables. Opcionales: cc, bcc, reply_to.

{
  "from": "App <noreply@tudominio.com>",
  "to": ["uno@ejemplo.com"],
  "subject": "Bienvenido, {{nombre}}",
  "template": "bienvenida",
  "variables": { "nombre": "Ana" }
}
→ 200 { "id": "01J2ZK7QW9..." }

Ejemplos en tu lenguaje:

curl -X POST https://zend24.com/api/v1/emails \
  -H "Authorization: Bearer sk_live_TU_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "from": "App <noreply@tudominio.com>",
    "to": "uno@ejemplo.com",
    "subject": "Bienvenido, Ana",
    "html": "<h1>Gracias por tu compra</h1>"
  }'
const res = await fetch("https://zend24.com/api/v1/emails", {
  method: "POST",
  headers: {
    "Authorization": "Bearer sk_live_TU_API_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    from: "App <noreply@tudominio.com>",
    to: "uno@ejemplo.com",
    subject: "Bienvenido, Ana",
    html: "<h1>Gracias por tu compra</h1>",
  }),
});
console.log(await res.json());
import requests

requests.post(
    "https://zend24.com/api/v1/emails",
    headers={"Authorization": "Bearer sk_live_TU_API_KEY"},
    json={
        "from": "App <noreply@tudominio.com>",
        "to": "uno@ejemplo.com",
        "subject": "Bienvenido, Ana",
        "html": "<h1>Gracias por tu compra</h1>",
    },
)
<?php
$ch = curl_init('https://zend24.com/api/v1/emails');
curl_setopt_array($ch, [
  CURLOPT_POST => true,
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_HTTPHEADER => ['Authorization: Bearer sk_live_TU_API_KEY', 'Content-Type: application/json'],
  CURLOPT_POSTFIELDS => json_encode([
    'from' => 'App <noreply@tudominio.com>', 'to' => 'uno@ejemplo.com',
    'subject' => 'Bienvenido, Ana', 'html' => '<h1>Gracias por tu compra</h1>',
  ]),
]);
echo curl_exec($ch);
require 'net/http'
require 'json'

uri = URI('https://zend24.com/api/v1/emails')
req = Net::HTTP::Post.new(uri, {
  'Authorization' => 'Bearer sk_live_TU_API_KEY',
  'Content-Type'  => 'application/json'
})
req.body = {
  from: 'App <noreply@tudominio.com>', to: 'uno@ejemplo.com',
  subject: 'Bienvenido, Ana', html: '<h1>Gracias por tu compra</h1>'
}.to_json
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |h| h.request(req) }
puts res.body
package main

import ("bytes"; "io"; "net/http")

func main() {
	body := []byte(`{"from":"App <noreply@tudominio.com>","to":"uno@ejemplo.com","subject":"Bienvenido, Ana","html":"<h1>Gracias por tu compra</h1>"}`)
	req, _ := http.NewRequest("POST", "https://zend24.com/api/v1/emails", bytes.NewBuffer(body))
	req.Header.Set("Authorization", "Bearer sk_live_TU_API_KEY")
	req.Header.Set("Content-Type", "application/json")
	res, _ := http.DefaultClient.Do(req)
	defer res.Body.Close()
	out, _ := io.ReadAll(res.Body)
	println(string(out))
}

Adjuntos

Añade el campo attachments (array). Cada elemento: filename, content (contenido del archivo en base64) y opcional content_type (MIME). Máximo 20 archivos y 1 MB en total.

{
  "from": "App <noreply@tudominio.com>",
  "to": "uno@ejemplo.com",
  "subject": "Tu factura de julio",
  "html": "<h1>Gracias por tu compra</h1>",
  "attachments": [
    {
      "filename": "factura.pdf",
      "content_type": "application/pdf",
      "content": "JVBERi0xLjQKJ..."   # base64
    }
  ]
}

POST /emails/batch

Hasta 100 envíos en una llamada: { "emails": [ {...}, {...} ] }. Devuelve resultado por índice.

GET /emails/{id} · GET /emails

Estado individual (status, opens, clicks) o listado paginado con ?limit=&before= (cursor).

GET /domains · GET /suppressions · DELETE /suppressions/{email}

Estado de dominios y gestión de la lista de supresión (DELETE requiere key con scope full).

Webhooks

Eventos: email.sent, email.delivered, email.bounced, email.complained, email.opened, email.clicked. Cada POST incluye X-Zend24-Timestamp y X-Zend24-Signature: v1=HMAC_SHA256(ts.body, secret). Verifica la firma y rechaza timestamps de más de 5 minutos.

Errores y límites

Errores: { "error": { "type", "message" } } con códigos HTTP estándar (401 auth, 403 dominio, 422 validación, 429 rate limit/cuota). El rate limit por minuto depende de tu plan.