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.comTodas 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ódigomessage— explicación del fallo en lenguaje llanostatusCode— el estado HTTPrequestId— único por solicitud; cítalo cuando escribas a soporteerrors— desglose de validación por campo, presente cuando aplicasuggestion— 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=abc123Parámetros:
limit— tamaño de página (por defecto: 20, máximo: 100)cursor— el valorcursordevuelto 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étodo | Ruta | Descripción | Clave |
|---|---|---|---|
| POST | /v1/send | Envía un correo transaccional — uno o varios destinatarios, plantilla o contenido en línea, con adjuntos, encabezados y datos personalizados. | sk_* |
| POST | /v1/track | Registra un evento en un contacto, creando o haciendo upsert del contacto según haga falta. Dispara workflows. | pk_* o sk_* |
| POST | /v1/verify | Comprueba una dirección de correo: formato, registros MX, dominios desechables, posibles errores tipográficos. | sk_* |
Contactos
| Método | Ruta | Descripción |
|---|---|---|
| GET | /contacts | Lista contactos, con search (subcadena de correo), limit y cursor soportados. |
| POST | /contacts | Crea o hace upsert de un contacto identificado por correo. La respuesta incluye _meta.isNew y _meta.isUpdate. |
| GET | /contacts/:id | Obtiene un contacto. |
| PATCH | /contacts/:id | Cambia el correo, el estado de suscripción o los campos data de un contacto. |
| DELETE | /contacts/:id | Elimina un contacto. |
| POST | /contacts/lookup | Comprueba cuáles de hasta 500 correos ya existen, en una sola llamada. |
| Campos personalizados | ||
| GET | /contacts/fields | Enumera campos estándar y personalizados, con tipos inferidos y porcentajes de cobertura. |
| GET | /contacts/fields/:field/values | Valores distintos de un campo personalizado — impulsa las interfaces de filtros de segmentos y workflows. |
| GET | /contacts/fields/:field/usage | Dónde aparece un campo personalizado (segmentos, campañas, workflows). |
| DELETE | /contacts/fields/:field | Elimina un campo personalizado de todos los contactos del proyecto. |
| Importación CSV | ||
| POST | /contacts/import | Sube un CSV (multipart, ≤ 5 MB). Se ejecuta como job encolado — devuelve un jobId. |
| GET | /contacts/import/:jobId | Consulta un job de importación CSV. |
| Operaciones masivas | ||
| POST | /contacts/bulk-subscribe | Suscribe hasta 1000 contactos por ID. Encolado — devuelve un jobId. |
| POST | /contacts/bulk-unsubscribe | Da de baja hasta 1000 contactos por ID. Encolado. |
| POST | /contacts/bulk-delete | Elimina hasta 1000 contactos por ID. Encolado. |
| GET | /contacts/bulk/:jobId | Consulta un job masivo. |
Plantillas
| Método | Ruta | Descripción |
|---|---|---|
| GET | /templates | Lista todas las plantillas. |
| POST | /templates | Crea una plantilla. Su dirección from debe pertenecer a un dominio verificado. |
| GET | /templates/:id | Obtiene una plantilla. |
| PATCH | /templates/:id | Edita una plantilla. |
| DELETE | /templates/:id | Elimina una plantilla. |
| POST | /templates/:id/duplicate | Copia una plantilla — devuelve el ID de la nueva plantilla. |
| GET | /templates/:id/usage | Qué campañas y pasos de workflow dependen de esta plantilla. |
Campañas
| Método | Ruta | Descripción |
|---|---|---|
| GET | /campaigns | Lista todas las campañas. |
| POST | /campaigns | Crea una campaña en DRAFT. Su dirección from debe pertenecer a un dominio verificado. |
| GET | /campaigns/:id | Obtiene una campaña. |
| PUT | /campaigns/:id | Reemplaza el contenido de una campaña. |
| DELETE | /campaigns/:id | Elimina una campaña — 409 si aún hay ejecuciones activas. |
| POST | /campaigns/:id/duplicate | Copia una campaña — recibes de vuelta la nueva en DRAFT. |
| POST | /campaigns/:id/send | Envía la campaña ahora, o más tarde vía scheduledFor. |
| POST | /campaigns/:id/cancel | Detiene una campaña que está SCHEDULED o SENDING. |
| POST | /campaigns/:id/test | Envía una prueba a una dirección ({ email: "you@example.com" }). |
| GET | /campaigns/:id/stats | Recuentos actuales de envíos / aperturas / clics / rebotes. |
Segmentos
| Método | Ruta | Descripción |
|---|---|---|
| GET | /segments | Lista todos los segmentos (sin paginar — la lista se mantiene pequeña). |
| POST | /segments | Crea un segmento. type: "DYNAMIC" requiere condition; type: "STATIC" la rechaza. |
| GET | /segments/:id | Obtiene un segmento, con el memberCount en caché incluido. |
| PATCH | /segments/:id | Edita el nombre, la descripción, la condición (solo dinámicos) o trackMembership. |
| DELETE | /segments/:id | Elimina un segmento — 409 si una campaña activa depende de él. |
| GET | /segments/:id/contacts | Listado 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/members | Añade correos a un segmento estático. Body: { emails, createMissing?, subscribed? }. |
| DELETE | /segments/:id/members | Quita correos de un segmento estático. Body: { emails }. |
| POST | /segments/:id/compute | Recalcula la membresía de un segmento dinámico monitoreado, emitiendo eventos de entrada/salida. |
| POST | /segments/:id/refresh | Actualizació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étodo | Ruta | Descripción |
|---|---|---|
| GET | /workflows | Lista todos los workflows. |
| GET | /workflows/fields | Campos de contacto y de evento utilizables dentro de los filtros de pasos CONDITION. |
| POST | /workflows | Crea un workflow. Siempre empieza con triggerType: EVENT y enabled: false. |
| GET | /workflows/:id | Obtiene un workflow junto con sus pasos y transiciones. |
| PATCH | /workflows/:id | Edita metadatos, el tipo/config del disparador, enabled o allowReentry. |
| DELETE | /workflows/:id | Elimina un workflow — solo cuando no queden ejecuciones activas (cancélalas o deja que terminen). |
| Pasos | ||
| POST | /workflows/:id/steps | Añade un paso (SEND_EMAIL, DELAY, WAIT_FOR_EVENT, CONDITION, WEBHOOK, UPDATE_CONTACT, EXIT). |
| PATCH | /workflows/:id/steps/:stepId | Edita la configuración de un paso. |
| DELETE | /workflows/:id/steps/:stepId?splice=true | Elimina un paso; con splice=true las transiciones circundantes se reconectan automáticamente. |
| Transiciones | ||
| POST | /workflows/:id/transitions | Conecta dos pasos. En pasos CONDITION, especifica branch: "yes" | "no". |
| DELETE | /workflows/:id/transitions/:transitionId | Elimina una transición. |
| Ejecuciones | ||
| POST | /workflows/:id/executions | Inicia una ejecución para un contacto manualmente. Acepta un context JSON opcional como variables por ejecución. |
| GET | /workflows/:id/executions | Lista ejecuciones; filtra por status. |
| GET | /workflows/:id/executions/:executionId | Obtiene una ejecución. |
| DELETE | /workflows/:id/executions/:executionId | Cancela una ejecución que esté en curso o en espera. |
| POST | /workflows/:id/executions/cancel-all | Cancela todas las ejecuciones activas de una sola vez. |
Eventos
| Método | Ruta | Descripción |
|---|---|---|
| POST | /events/track | Alias orientado al panel de /v1/track. El código de tu aplicación debería llamar a /v1/track en su lugar. |
| GET | /events | Eventos recientes registrados en todo el proyecto. |
| GET | /events/stats | Estadísticas de eventos, agregadas. |
| GET | /events/contact/:contactId | El historial completo de eventos de un contacto. |
| GET | /events/names | Todos los nombres de evento distintos que el proyecto ha registrado. |
| GET | /events/:eventName/usage | Dónde se usa un nombre de evento (filtros de segmento, disparadores de workflow, condiciones). |
| DELETE | /events/:eventName | Purga todos los eventos con ese nombre del proyecto. |
Dominios
| Método | Ruta | Descripción |
|---|---|---|
| GET | /domains/project/:projectId | Dominios adjuntos a un proyecto, tanto verificados como pendientes. |
| POST | /domains | Registra un dominio para verificación y recibe los registros DNS a publicar. |
| GET | /domains/:id/verify | Ejecuta una verificación de inmediato (la comprobación en segundo plano igualmente corre cada 5 minutos). |
| DELETE | /domains/:id | Desvincula un dominio. |
Actividad y analíticas
| Método | Ruta | Descripción |
|---|---|---|
| GET | /activity | Feed de actividad que abarca todos los recursos (envíos, aperturas, clics, rebotes, quejas, entrantes, etc.). |
| GET | /activity/stats | Recuentos agregados que alimentan los gráficos del panel. |
| GET | /activity/recent-count | Recuento de eventos recientes, usado por el indicador "en vivo" del panel. |
| GET | /activity/types | Los tipos de actividad presentes en el proyecto. |
| GET | /activity/upcoming | Envíos y ejecuciones programados que se acercan. |
| GET | /analytics/timeseries | Recuentos de envíos / aperturas / clics a lo largo del tiempo. |
| GET | /analytics/top-campaigns | Campañas con mejor rendimiento, clasificadas por métrica. |
| GET | /analytics/campaign-stats | Desglose por campaña. |
| GET | /analytics/top-events | Nombres de eventos personalizados clasificados por frecuencia. |
Subidas
| Método | Ruta | Descripción |
|---|---|---|
| POST | /uploads/image | Sube 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étodo | Ruta | Descripción |
|---|---|---|
| POST | /auth/login | Inicia sesión con correo y contraseña; establece una cookie JWT. |
| POST | /auth/signup | Registra un usuario (respeta DISABLE_SIGNUPS). |
| GET | /auth/logout | Elimina la cookie de sesión. |
| GET | /auth/oauth-config | Los proveedores OAuth configurados actualmente. |
| POST | /auth/verify-email | Confirma un correo usando el token del enlace enviado por correo. |
| POST | /auth/request-verification | Vuelve a enviar el correo de verificación. |
| POST | /auth/request-password-reset | Envía por correo un enlace de restablecimiento de contraseña. |
| POST | /auth/reset-password | Establece una nueva contraseña usando un token. |
| GET | /users/@me | El usuario con la sesión iniciada actualmente. |
| GET | /users/@me/projects | Proyectos pertenecientes al usuario. |
| POST | /users/@me/projects | Crea un proyecto. |
| PATCH | /users/@me/projects/:id | Edita la configuración del proyecto. |
| POST | /users/@me/projects/:id/checkout | Inicia una sesión de Stripe Checkout. |
| POST | /users/@me/projects/:id/billing-portal | Abre el portal de facturación de Stripe. |
| GET | /users/@me/projects/:id/billing-limits | Lee los límites de facturación por categoría. |
| PUT | /users/@me/projects/:id/billing-limits | Cambia los límites de facturación por categoría. |
| GET | /users/@me/projects/:id/billing-consumption | Consumo en el período de facturación actual. |
| GET | /users/@me/projects/:id/billing-invoices | Las facturas de Stripe del proyecto. |
| GET | /users/@me/projects/:id/security | Resumen de seguridad — tasas de rebote/queja, suspensiones recientes. |
| POST | /users/@me/projects/:id/reset | Borra todos los datos del proyecto (no se puede deshacer). |
| DELETE | /users/@me/projects/:id | Elimina el proyecto completo. |
| GET | /projects/:id/setup-state | Estado de progreso de la incorporación. |
| GET | /projects/:id/security | Estado de seguridad de un proyecto. |
| GET | /projects/:id/members | Los miembros del equipo del proyecto. |
| POST | /projects/:id/members | Invita a alguien al equipo. |
| PATCH | /projects/:id/members/:userId | Actualiza el rol de un miembro. |
| DELETE | /projects/:id/members/:userId | Elimina 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étodo | Ruta | Descripción |
|---|---|---|
| POST | /apikeys | Crea una clave secreta con alcance. Devuelve su valor en texto plano una vez, nunca más. |
| GET | /apikeys | Lista las claves del proyecto (nombre, prefijo, alcances, marcas de tiempo — nunca la clave). |
| POST | /apikeys/:id/revoke | Revoca una clave de inmediato; el resto sigue funcionando. |
Configuración
| Método | Ruta | Descripción |
|---|---|---|
| GET | /config | Endpoint 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étodo | Ruta |
|---|---|
| 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"}'