Saltar al contenido
Docs · API

Batch, rates y errores.

Más allá del envío unitario: ingesta masiva con éxito parcial, métricas del tenant, el envelope de error uniforme, certificado vs plain y la verificación online de la evidencia.

  1. 01POST /v1/messages/batch

    Ingesta batch (≤100)

    Un solo request JSON con hasta 100 mensajes. Cada ítem lleva su propio idempotency_key. La respuesta lista resultados por índice y contadores created / failed / replayed.

    max 100partial successempty_batchbatch_too_large
    POST /v1/messages/batch
    curl -s -X POST "$MAILACK_API_URL/v1/messages/batch" \
      -H "Authorization: Bearer $MAILACK_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
        "messages": [
          {
            "idempotency_key": "order-1",
            "from": "noreply@acme.mx",
            "to": "a@ejemplo.com",
            "subject": "Pedido 1",
            "text": "Gracias"
          },
          {
            "idempotency_key": "order-2",
            "from": "noreply@acme.mx",
            "to": "b@ejemplo.com",
            "subject": "Pedido 2",
            "text": "Gracias"
          }
        ]
      }' | jq .
  2. 02GET /v1/rates

    Rates de entregabilidad

    Agregados del tenant en una ventana de días (query days, default 14): ingested, sent, deferred, bounced, complained, sealed, tasas y serie diaria. Misma forma en el portal (pantalla Rates).

    Son métricas operativas del tenant, no un claim de entregabilidad pública del producto.

    GET /v1/rates?days=14
    curl -s "$MAILACK_API_URL/v1/rates?days=14" \
      -H "Authorization: Bearer $MAILACK_API_KEY" | jq .
  3. 03auth

    Scopes de API key

    La key Bearer resuelve el tenant. Scopes habituales:

    messages:sendenvío, batch, dominios, webhooks, templates
    evidence:readlectura, listados, rates, proof-bundle
    suppressions:writesupresiones
    api_keys:writegestión de keys del tenant
  4. 04errores

    Envelope, códigos y HTTP status

    Formato uniforme: {"error":{"code":"snake_case","message":"…"}}. El message es legible y suele indicar la corrección (p. ej. "add and verify it in the portal"). Cada código va siempre con el mismo HTTP status:

    400 · missing_idempotency_keyfalta el header Idempotency-Key en la ingesta; es obligatorio y hace seguro el reintento
    400 · invalid_bodyJSON malformado o sin contenido: se requiere al menos uno de text o html
    400 · invalid_addressdirección From/To vacía o con formato inválido
    401 · unauthorizedAPI key ausente o inválida en Authorization: Bearer
    403 · insufficient_scopela key es válida pero no tiene el scope que exige la ruta
    403 · tenant_suspended / tenant_deactivatedla cuenta está suspendida o desactivada; contacta a soporte
    404 · not_foundel recurso no existe (o no es visible para tu tenant: una lectura cruzada responde 404, no 403)
    404 · template_not_foundel template_id del envío no existe en el tenant
    415 · unsupported_media_typeContent-Type distinto de application/json o message/rfc822
    422 · domain_not_verifiedel dominio del From no está verificado en tu cuenta; regístralo, publica el TXT de challenge y verifícalo (guía de Dominios)
    422 · from_not_approvedel remitente no está aprobado como sender activo del dominio verificado
    422 · recipient_suppressedel destinatario está en la lista de supresión (global o del tenant); el dispatcher no lo encola
    422 · template_render_errorfallo al renderizar las {{variables}} de la plantilla con los datos enviados
    422 · not_certifiedse intentó sellar un mensaje enviado con certified=false; no hay upgrade silencioso a certificado
    422 · missing_proof_datael mensaje aún no está sellado en un batch Merkle (o es plain y nunca lo estará); reintenta tras el sellado
    429 · quota_exceededcuota mensual agotada; el message distingue la bolsa ("certified" o "plain"). Bolsas independientes por mes natural UTC: agotar una no bloquea la otra; el replay idempotente no consume cuota

    El listado completo y normativo de códigos vive en el contrato OpenAPI del repositorio (docs/openapi.yaml, schema Error). Esta tabla cubre los errores que verás al integrar el envío.

  5. 05superficies

    Machine, portal y admin

    Machine API (/v1/* con API key) es la de SDKs y MCP. Portal (/v1/portal/*) usa sesión del usuario del cliente. Admin (/v1/admin/*) es la consola de operadores JAAK.

    API keyportal sessionadmin session
  6. 06certified

    Certificado vs plain

    Cada mensaje lleva una bandera certified. El envío JSON acepta el override por mensaje "certified": false; si lo omites, aplica el default de la cuenta (default_certified). Los cuerpos message/rfc822 no admiten override: siempre usan el default. Un mensaje plain entrega igual, pero no entra al árbol Merkle: sellarlo responde 422 not_certified y su proof-bundle 422 missing_proof_data. No hay upgrade silencioso a certificado.

    certified=truecanonicalizado, hoja Merkle, sellable con NOM-151; bolsa quota_messages_month
    certified=falseentrega transaccional con transcript SMTP y DSN, sin sello; bolsa quota_plain_messages_month
    cuotas independientesagotar la bolsa plain no bloquea la certificada, y viceversa
    facturaciónprice_per_message_cents (certificado) y price_per_plain_message_cents (plain), por cuenta
    POST /v1/messages con certified=false
    curl -s -X POST "$MAILACK_API_URL/v1/messages" \
      -H "Authorization: Bearer $MAILACK_API_KEY" \
      -H "Idempotency-Key: $(uuidgen)" \
      -H "Content-Type: application/json" \
      -d '{
        "from": "noreply@acme.mx",
        "to": "cliente@ejemplo.com",
        "subject": "Aviso operativo",
        "html": "<p>Mensaje transaccional sin certificación.</p>",
        "certified": false
      }' | jq '{id, certified}'
  7. 07GET /v1/messages/{id}/evidence · POST /v1/verify

    Evidencia y verificación online

    Además del proof-bundle descargable —que cualquiera puede comprobar en mailack.com/verificar, en su navegador y sin subir nada—, la API expone la evidencia en línea: /evidence devuelve el resumen del mensaje sellado (hash canónico, batch_id, raíz Merkle, certificate_id, sealed_at) y /v1/verify recomputa la prueba de inclusión Merkle por message_id y responde valid: true|false. Cada consulta de verificación queda en el access log.

    evidenceverify onlineproof-bundle
    GET /v1/messages/{id}/evidence · POST /v1/verify
    # Resumen de evidencia del mensaje (hash, batch, raíz Merkle, constancia)
    curl -s "$MAILACK_API_URL/v1/messages/$MESSAGE_ID/evidence" \
      -H "Authorization: Bearer $MAILACK_API_KEY" | jq .
    
    # Verificación online de la prueba de inclusión Merkle
    curl -s -X POST "$MAILACK_API_URL/v1/verify" \
      -H "Authorization: Bearer $MAILACK_API_KEY" \
      -H "Content-Type: application/json" \
      -d "{\"message_id\": \"$MESSAGE_ID\"}" | jq .
    # → {"valid": true, "merkle_root": "…", "certificate_id": "…", "sealed_at": "…"}

SDKs oficiales

Los mismos endpoints envueltos en Go, Rust, JS, Node, Python, Java y C#.