BitelioBitelio
Referencia de API

Referencia de la API

Todo lo que expone la API de Bitelio — autenticación, formato de las solicitudes, paginación, límites de tasa y el catálogo completo de endpoints

URL base

https://api.bitelio.com

Todas las solicitudes van a esta URL base.

Autenticación

Pasa tu clave de API como token bearer en el encabezado Authorization:

Authorization: Bearer YOUR_API_KEY
  • Clave secreta (sk_*) — necesaria en todos los endpoints excepto /v1/track
  • Clave pública (pk_*) — solo se acepta en /v1/track, para que puedas registrar eventos desde código del lado del cliente

Cómo hacer solicitudes

Enviar un correo transaccional

curl -X POST https://api.bitelio.com/v1/send \
  -H "Authorization: Bearer sk_your_secret_key" \
  -H "Content-Type: application/json" \
  -d '{
    "to": "user@example.com",
    "subject": "Hello",
    "body": "<p>Your message here</p>"
  }'

Registrar un evento

curl -X POST https://api.bitelio.com/v1/track \
  -H "Authorization: Bearer pk_your_public_key" \
  -H "Content-Type: application/json" \
  -d '{
    "email": "user@example.com",
    "event": "signed_up"
  }'

Crear un contacto

curl -X POST https://api.bitelio.com/contacts \
  -H "Authorization: Bearer sk_your_secret_key" \
  -H "Content-Type: application/json" \
  -d '{
    "email": "user@example.com",
    "subscribed": true,
    "data": {
      "firstName": "John",
      "plan": "pro"
    }
  }'

Formato de respuesta

Respuestas de éxito

Los endpoints públicos (/v1/send, /v1/track, /v1/verify) envuelven su payload en un sobre:

{
  "success": true,
  "data": {
    "contact": "cnt_abc123",
    "event": "evt_xyz789",
    "timestamp": "2025-11-30T10:30:00.000Z"
  }
}

Los endpoints tipo panel (contactos, plantillas, campañas, segmentos, workflows, etc.) omiten el sobre success/data y devuelven directamente el recurso:

{
  "id": "cnt_abc123",
  "email": "user@example.com",
  "createdAt": "2025-11-30T10:30:00.000Z"
}

Los endpoints de listado con paginación por cursor responden con:

{
  "data": [ /* items */ ],
  "cursor": "def456",
  "hasMore": true,
  "total": 10000
}

Respuesta de error

Cada error trae suficiente detalle como para depurarlo directamente:

{
  "success": false,
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Request validation failed",
    "statusCode": 422,
    "requestId": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
    "errors": [
      {
        "field": "email",
        "message": "Invalid email",
        "code": "invalid_string"
      }
    ],
    "suggestion": "One or more fields have incorrect types. Check that strings are quoted, numbers are unquoted, and booleans are true/false."
  },
  "timestamp": "2025-11-30T10:30:00.000Z"
}

Campos del error:

  • code — identificador estable y legible por máquina sobre el que puedes ramificar tu código
  • message — explicación del fallo en lenguaje llano
  • statusCode — el estado HTTP
  • requestId — único por solicitud; cítalo cuando escribas a soporte
  • errors — desglose de validación por campo, presente cuando aplica
  • suggestion — una pista sobre cómo resolver el problema

La documentación de códigos de error cubre todos los códigos con ejemplos resueltos.

Paginación

La paginación basada en cursor es la norma en los endpoints de listado:

GET /contacts?limit=100&cursor=abc123

Parámetros:

  • limit — tamaño de página (por defecto: 20, máximo: 100)
  • cursor — el valor cursor devuelto por la página anterior

Respuesta:

{
  "data": [ /* items */ ],
  "cursor": "def456",
  "hasMore": true,
  "total": 10000
}

Pasa el cursor de cada respuesta al parámetro de consulta cursor de la siguiente solicitud, y detente cuando hasMore venga false. Solo la primera página (la que se pide sin cursor) calcula total; las páginas siguientes reportan total: 0 para que el listado siga siendo rápido.

Un puñado de endpoints (p. ej. GET /segments/:id/contacts) pagina por número de página en su lugar, tomando page y pageSize y devolviendo total, page y pageSize en la respuesta.

Límites de tasa

Para mantener el servicio saludable para todos, Bitelio aplica límites razonables:

  • Envío de correos — regulado por proyecto para proteger la entregabilidad.
  • Solicitudes de API — 1000 solicitudes/minuto por proyecto.
  • Operaciones masivas — se encolan automáticamente para procesamiento asíncrono.

Superar un límite te devuelve una respuesta 429 Too Many Requests.

Códigos de error

Los errores combinan códigos de estado HTTP estándar con identificadores de código legibles por máquina:

400 Bad Request — Los parámetros son inválidos o el cuerpo de la solicitud está mal formado

401 Unauthorized — Falta la clave de API o no es válida

403 Forbidden — No tienes acceso al recurso, o el proyecto está deshabilitado

404 Not Found — No existe ese recurso

422 Unprocessable Entity — La validación rechazó la solicitud (el array errors explica por qué)

429 Too Many Requests — Alcanzaste un límite de tasa

500 Internal Server Error — Algo falló de nuestro lado (envía a soporte el ID de la solicitud)

El catálogo completo, con pasos de resolución de problemas, está en la documentación de códigos de error.

Endpoints de la API

Todos los endpoints que expone la API de Bitelio, agrupados por recurso.

API pública

Las rutas /v1/* existen para el código de tu aplicación y toman payloads planos y desnormalizados. De todos los endpoints, solo POST /v1/track acepta una clave pública (pk_*).

MétodoRutaDescripciónClave
POST/v1/sendEnvía un correo transaccional — uno o varios destinatarios, plantilla o contenido en línea, con adjuntos, encabezados y datos personalizados.sk_*
POST/v1/trackRegistra un evento en un contacto, creando o haciendo upsert del contacto según haga falta. Dispara workflows.pk_* o sk_*
POST/v1/verifyComprueba una dirección de correo: formato, registros MX, dominios desechables, posibles errores tipográficos.sk_*

Contactos

MétodoRutaDescripción
GET/contactsLista contactos, con search (subcadena de correo), limit y cursor soportados.
POST/contactsCrea o hace upsert de un contacto identificado por correo. La respuesta incluye _meta.isNew y _meta.isUpdate.
GET/contacts/:idObtiene un contacto.
PATCH/contacts/:idCambia el correo, el estado de suscripción o los campos data de un contacto.
DELETE/contacts/:idElimina un contacto.
POST/contacts/lookupComprueba cuáles de hasta 500 correos ya existen, en una sola llamada.
Campos personalizados
GET/contacts/fieldsEnumera campos estándar y personalizados, con tipos inferidos y porcentajes de cobertura.
GET/contacts/fields/:field/valuesValores distintos de un campo personalizado — impulsa las interfaces de filtros de segmentos y workflows.
GET/contacts/fields/:field/usageDónde aparece un campo personalizado (segmentos, campañas, workflows).
DELETE/contacts/fields/:fieldElimina un campo personalizado de todos los contactos del proyecto.
Importación CSV
POST/contacts/importSube un CSV (multipart, ≤ 5 MB). Se ejecuta como job encolado — devuelve un jobId.
GET/contacts/import/:jobIdConsulta un job de importación CSV.
Operaciones masivas
POST/contacts/bulk-subscribeSuscribe hasta 1000 contactos por ID. Encolado — devuelve un jobId.
POST/contacts/bulk-unsubscribeDa de baja hasta 1000 contactos por ID. Encolado.
POST/contacts/bulk-deleteElimina hasta 1000 contactos por ID. Encolado.
GET/contacts/bulk/:jobIdConsulta un job masivo.

Plantillas

MétodoRutaDescripción
GET/templatesLista todas las plantillas.
POST/templatesCrea una plantilla. Su dirección from debe pertenecer a un dominio verificado.
GET/templates/:idObtiene una plantilla.
PATCH/templates/:idEdita una plantilla.
DELETE/templates/:idElimina una plantilla.
POST/templates/:id/duplicateCopia una plantilla — devuelve el ID de la nueva plantilla.
GET/templates/:id/usageQué campañas y pasos de workflow dependen de esta plantilla.

Campañas

MétodoRutaDescripción
GET/campaignsLista todas las campañas.
POST/campaignsCrea una campaña en DRAFT. Su dirección from debe pertenecer a un dominio verificado.
GET/campaigns/:idObtiene una campaña.
PUT/campaigns/:idReemplaza el contenido de una campaña.
DELETE/campaigns/:idElimina una campaña — 409 si aún hay ejecuciones activas.
POST/campaigns/:id/duplicateCopia una campaña — recibes de vuelta la nueva en DRAFT.
POST/campaigns/:id/sendEnvía la campaña ahora, o más tarde vía scheduledFor.
POST/campaigns/:id/cancelDetiene una campaña que está SCHEDULED o SENDING.
POST/campaigns/:id/testEnvía una prueba a una dirección ({ email: "you@example.com" }).
GET/campaigns/:id/statsRecuentos actuales de envíos / aperturas / clics / rebotes.

Segmentos

MétodoRutaDescripción
GET/segmentsLista todos los segmentos (sin paginar — la lista se mantiene pequeña).
POST/segmentsCrea un segmento. type: "DYNAMIC" requiere condition; type: "STATIC" la rechaza.
GET/segments/:idObtiene un segmento, con el memberCount en caché incluido.
PATCH/segments/:idEdita el nombre, la descripción, la condición (solo dinámicos) o trackMembership.
DELETE/segments/:idElimina un segmento — 409 si una campaña activa depende de él.
GET/segments/:id/contactsListado de miembros paginado por página vía page y pageSize (máx. 100). Se evalúa en vivo para segmentos dinámicos.
POST/segments/:id/membersAñade correos a un segmento estático. Body: { emails, createMissing?, subscribed? }.
DELETE/segments/:id/membersQuita correos de un segmento estático. Body: { emails }.
POST/segments/:id/computeRecalcula la membresía de un segmento dinámico monitoreado, emitiendo eventos de entrada/salida.
POST/segments/:id/refreshActualización ligera del recuento — no se emiten eventos, no se escribe membresía.

Workflows

Un workflow se guarda como un registro de workflow más un grafo de pasos, las transiciones que los conectan, y una ejecución por cada contacto que pasa por él. Los endpoints siguen esa misma estructura.

MétodoRutaDescripción
GET/workflowsLista todos los workflows.
GET/workflows/fieldsCampos de contacto y de evento utilizables dentro de los filtros de pasos CONDITION.
POST/workflowsCrea un workflow. Siempre empieza con triggerType: EVENT y enabled: false.
GET/workflows/:idObtiene un workflow junto con sus pasos y transiciones.
PATCH/workflows/:idEdita metadatos, el tipo/config del disparador, enabled o allowReentry.
DELETE/workflows/:idElimina un workflow — solo cuando no queden ejecuciones activas (cancélalas o deja que terminen).
Pasos
POST/workflows/:id/stepsAñade un paso (SEND_EMAIL, DELAY, WAIT_FOR_EVENT, CONDITION, WEBHOOK, UPDATE_CONTACT, EXIT).
PATCH/workflows/:id/steps/:stepIdEdita la configuración de un paso.
DELETE/workflows/:id/steps/:stepId?splice=trueElimina un paso; con splice=true las transiciones circundantes se reconectan automáticamente.
Transiciones
POST/workflows/:id/transitionsConecta dos pasos. En pasos CONDITION, especifica branch: "yes" | "no".
DELETE/workflows/:id/transitions/:transitionIdElimina una transición.
Ejecuciones
POST/workflows/:id/executionsInicia una ejecución para un contacto manualmente. Acepta un context JSON opcional como variables por ejecución.
GET/workflows/:id/executionsLista ejecuciones; filtra por status.
GET/workflows/:id/executions/:executionIdObtiene una ejecución.
DELETE/workflows/:id/executions/:executionIdCancela una ejecución que esté en curso o en espera.
POST/workflows/:id/executions/cancel-allCancela todas las ejecuciones activas de una sola vez.

Eventos

MétodoRutaDescripción
POST/events/trackAlias orientado al panel de /v1/track. El código de tu aplicación debería llamar a /v1/track en su lugar.
GET/eventsEventos recientes registrados en todo el proyecto.
GET/events/statsEstadísticas de eventos, agregadas.
GET/events/contact/:contactIdEl historial completo de eventos de un contacto.
GET/events/namesTodos los nombres de evento distintos que el proyecto ha registrado.
GET/events/:eventName/usageDónde se usa un nombre de evento (filtros de segmento, disparadores de workflow, condiciones).
DELETE/events/:eventNamePurga todos los eventos con ese nombre del proyecto.

Dominios

MétodoRutaDescripción
GET/domains/project/:projectIdDominios adjuntos a un proyecto, tanto verificados como pendientes.
POST/domainsRegistra un dominio para verificación y recibe los registros DNS a publicar.
GET/domains/:id/verifyEjecuta una verificación de inmediato (la comprobación en segundo plano igualmente corre cada 5 minutos).
DELETE/domains/:idDesvincula un dominio.

Actividad y analíticas

MétodoRutaDescripción
GET/activityFeed de actividad que abarca todos los recursos (envíos, aperturas, clics, rebotes, quejas, entrantes, etc.).
GET/activity/statsRecuentos agregados que alimentan los gráficos del panel.
GET/activity/recent-countRecuento de eventos recientes, usado por el indicador "en vivo" del panel.
GET/activity/typesLos tipos de actividad presentes en el proyecto.
GET/activity/upcomingEnvíos y ejecuciones programados que se acercan.
GET/analytics/timeseriesRecuentos de envíos / aperturas / clics a lo largo del tiempo.
GET/analytics/top-campaignsCampañas con mejor rendimiento, clasificadas por métrica.
GET/analytics/campaign-statsDesglose por campaña.
GET/analytics/top-eventsNombres de eventos personalizados clasificados por frecuencia.

Subidas

MétodoRutaDescripción
POST/uploads/imageSube una imagen (multipart) para incrustarla en el cuerpo de las plantillas. Responde con una URL pública.

Autenticación y gestión de usuarios

Estas rutas dan soporte al panel, que inicia sesión con cookies JWT. Rara vez importan para el trabajo servidor a servidor, pero se incluye la lista para que nada quede sin documentar.

MétodoRutaDescripción
POST/auth/loginInicia sesión con correo y contraseña; establece una cookie JWT.
POST/auth/signupRegistra un usuario (respeta DISABLE_SIGNUPS).
GET/auth/logoutElimina la cookie de sesión.
GET/auth/oauth-configLos proveedores OAuth configurados actualmente.
POST/auth/verify-emailConfirma un correo usando el token del enlace enviado por correo.
POST/auth/request-verificationVuelve a enviar el correo de verificación.
POST/auth/request-password-resetEnvía por correo un enlace de restablecimiento de contraseña.
POST/auth/reset-passwordEstablece una nueva contraseña usando un token.
GET/users/@meEl usuario con la sesión iniciada actualmente.
GET/users/@me/projectsProyectos pertenecientes al usuario.
POST/users/@me/projectsCrea un proyecto.
PATCH/users/@me/projects/:idEdita la configuración del proyecto.
POST/users/@me/projects/:id/checkoutInicia una sesión de Stripe Checkout.
POST/users/@me/projects/:id/billing-portalAbre el portal de facturación de Stripe.
GET/users/@me/projects/:id/billing-limitsLee los límites de facturación por categoría.
PUT/users/@me/projects/:id/billing-limitsCambia los límites de facturación por categoría.
GET/users/@me/projects/:id/billing-consumptionConsumo en el período de facturación actual.
GET/users/@me/projects/:id/billing-invoicesLas facturas de Stripe del proyecto.
GET/users/@me/projects/:id/securityResumen de seguridad — tasas de rebote/queja, suspensiones recientes.
POST/users/@me/projects/:id/resetBorra todos los datos del proyecto (no se puede deshacer).
DELETE/users/@me/projects/:idElimina el proyecto completo.
GET/projects/:id/setup-stateEstado de progreso de la incorporación.
GET/projects/:id/securityEstado de seguridad de un proyecto.
GET/projects/:id/membersLos miembros del equipo del proyecto.
POST/projects/:id/membersInvita a alguien al equipo.
PATCH/projects/:id/members/:userIdActualiza el rol de un miembro.
DELETE/projects/:id/members/:userIdElimina a alguien del equipo.

Claves de API

Claves secretas con alcance, por proyecto. Consulta la guía de claves de API para ver el catálogo de permisos y las reglas de creación. Las tres requieren una sesión de panel con inicio de sesión y el permiso apikeys:manage — ninguna puede llamarse con una clave de API.

MétodoRutaDescripción
POST/apikeysCrea una clave secreta con alcance. Devuelve su valor en texto plano una vez, nunca más.
GET/apikeysLista las claves del proyecto (nombre, prefijo, alcances, marcas de tiempo — nunca la clave).
POST/apikeys/:id/revokeRevoca una clave de inmediato; el resto sigue funcionando.

Configuración

MétodoRutaDescripción
GET/configEndpoint de feature-flags sin autenticación — reporta qué integraciones están activas (proveedores OAuth, facturación, S3, SMTP, …).

Endpoints internos de webhook

La infraestructura de correo y facturación entrega aquí sus eventos. Tus aplicaciones nunca llaman a estos — aparecen solo para que la lista esté completa.

MétodoRuta
POST/webhooks/sns
POST/webhooks/incoming/stripe

Bibliotecas cliente

Node.js

const BITELIO_SECRET_KEY = process.env.BITELIO_SECRET_KEY;

async function sendEmail(to, subject, body) {
  const response = await fetch('https://api.bitelio.com/v1/send', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${BITELIO_SECRET_KEY}`,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({ to, subject, body })
  });

  const data = await response.json();

  if (!data.success) {
    throw new Error(`[${data.error.code}] ${data.error.message}`);
  }

  return data.data;
}

Python

import os
import requests

BITELIO_SECRET_KEY = os.environ['BITELIO_SECRET_KEY']

def send_email(to, subject, body):
    response = requests.post(
        'https://api.bitelio.com/v1/send',
        headers={
            'Authorization': f'Bearer {BITELIO_SECRET_KEY}',
            'Content-Type': 'application/json'
        },
        json={'to': to, 'subject': subject, 'body': body}
    )

    data = response.json()

    if not data.get('success'):
        error = data['error']
        raise Exception(f"[{error['code']}] {error['message']}")

    return data['data']

cURL

curl -X POST https://api.bitelio.com/v1/send \
  -H "Authorization: Bearer $BITELIO_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{"to": "user@example.com", "subject": "Hello", "body": "Message"}'

Qué sigue