EVENTIUM · API v1
Integra tus herramientas
URL base: https://myeventium.com/api/v1. API para integraciones desde servidor. El acceso al panel se activa después de la llamada con nuestro equipo.
1. Tu primera petición
Crea una clave de pruebas con el permiso events:read. Guárdala como EVENTIUM_API_KEY en el servidor. No la incluyas en JavaScript público, repositorios, URLs ni aplicaciones móviles.
curl https://myeventium.com/api/v1/events \ -H "Authorization: Bearer $EVENTIUM_API_KEY"
const response = await fetch('https://myeventium.com/api/v1/events', {
headers: { Authorization: `Bearer ${process.env.EVENTIUM_API_KEY}` }
});
if (!response.ok) throw new Error(await response.text());
const { data, next_cursor } = await response.json();También se acepta la cabecera x-api-key. Las claves sk_test_ usan datos ficticios; las sk_live_ acceden únicamente a los datos de tu cuenta. Caducan a los 30, 90 o 365 días según tu selección. Si revocas la clave o pierdes el acceso aprobado, dejará de funcionar.
events:readorders:readattendees:readcheckout:write
Rotación: crea una nueva clave, cambia el secreto en tu integración y revoca la anterior después de comprobar el cambio.
2. Endpoints disponibles
| Ruta | Permiso | Uso |
|---|---|---|
| GET /events | events:read | Eventos propios. status=draft|published. |
| GET /events/{id} | events:read | Detalle de un evento propio. |
| GET /events/{id}/tiers | events:read | Tipos de entrada y disponibilidad orientativa. |
| GET /orders | orders:read | Ventas de entradas, merch, pases, depósitos VIP y recargas. Filtros event_id y type. |
| GET /orders/{id} | orders:read | Detalle de una venta. |
| GET /refunds | orders:read | Ventas con importe reembolsado acumulado registrado; no inicia devoluciones. |
| GET /attendees?event_id=… | attendees:read | Titulares de entradas del evento. Una fila puede representar varias entradas. |
| POST /checkout/sessions | checkout:write | Enlace temporal al formulario de compra. Requiere Idempotency-Key. |
Eventos, ventas, devoluciones y asistentes admiten limit (1–100, por defecto 25) y cursor. Usa next_cursor mientras has_more sea true. El cursor es opaco. Los importes se expresan en unidades de la moneda: 20 EUR significa 20 €, no 20 céntimos.
La disponibilidad es una foto orientativa y no reserva entradas. Las devoluciones solo reflejan lo registrado en Eventium: una devolución manual en el banco no aparece automáticamente. En VIP, total_amount representa el depósito cobrado. Los pases no ofrecen un importe acumulado de devolución hasta que su flujo lo registre.
attendees contiene datos personales con permiso separado. marketing_consent=null significa desconocido: comprar una entrada no autoriza campañas de marketing. No se exponen códigos QR ni secretos de acceso.
3. Vender desde tu web
Tu servidor crea un enlace y redirige al comprador a la URL recibida. Eventium muestra el formulario habitual con la configuración del organizador; el comprador elige cantidad y acepta las condiciones. El precio, las promociones y el stock se validan al comprar. El cobro utiliza tu Stripe o Redsys configurado, sin comisión de software de Eventium.
curl https://myeventium.com/api/v1/checkout/sessions \
-H "Authorization: Bearer $EVENTIUM_API_KEY" \
-H 'Content-Type: application/json' \
-H 'Idempotency-Key: order-example-0001' \
-d '{"event_id":"11111111-1111-4111-8111-111111111111", "tier_id":"22222222-2222-4222-8222-222222222222"}'Este ejemplo usa los IDs del modo de pruebas. La clave necesita checkout:write. El enlace dura 30 minutos y no reserva inventario ni congela precios. Repetir Idempotency-Key con los mismos parámetros devuelve el mismo enlace; con otros parámetros devuelve 409. Tras caducar, utiliza una clave nueva. No se crea una sesión bancaria hasta que el comprador inicia el pago.
4. Webhooks firmados y recuperables
Añade una URL HTTPS pública en el panel, elige el evento y guarda el secreto. No se permiten destinos privados, credenciales en URL ni redirecciones. Las suscripciones de pruebas y producción están separadas. Puedes enviar webhook.test a cualquier suscripción con el botón Probar.
event.createdevent.updatedorder.completedorder.refundedticket.refundedcheckin.scannedwebhook.test
Los cambios se encolan en la misma transacción de base de datos. El worker revisa entregas cada minuto y realiza hasta 10 intentos, con esperas crecientes. El timeout del receptor es 8 segundos. Devuelve 2xx cuando hayas guardado el evento de forma duradera. No se garantiza el orden y puede haber duplicados: deduplica por id. Después de agotar los intentos, revisa el fallo y reenvía desde el panel. Los registros se conservan 30 días.
{
"id": "44444444-4444-4444-8444-444444444444",
"type": "order.completed",
"created": 1791158400,
"livemode": true,
"data": { "order_id": "33333333-3333-4333-8333-333333333333", "resource_type": "ticket", "total_amount": 20, "currency": "EUR" }
}Cabeceras: X-Eventium-Signature (t=timestamp,v1=firma), X-Eventium-Event-Id, X-Eventium-Delivery-Id y X-Eventium-Event-Type. Los avisos de venta y devolución cubren cambios registrados por ambas pasarelas. ticket.refunded es un alias específico para entradas; si escuchas también order.refunded, evita aplicar dos veces la misma lógica.
import { createHmac, timingSafeEqual } from 'node:crypto';
export function verify(rawBody, header, secret) {
if (typeof header !== 'string') return false;
const parts = Object.fromEntries(header.split(',').map(p => p.split('=')));
const timestamp = Number(parts.t);
if (!Number.isInteger(timestamp) || !/^[a-f0-9]{64}$/.test(parts.v1 ?? '')) return false;
if (Math.abs(Date.now() / 1000 - timestamp) > 300) return false;
const expected = createHmac('sha256', secret)
.update(`${timestamp}.${rawBody}`).digest();
return timingSafeEqual(expected, Buffer.from(parts.v1, 'hex'));
}
// Verify the unmodified raw request body before JSON.parse().
// Persist event.id with a UNIQUE constraint in the same transaction
// as your business change. A duplicate event must return 2xx without
// applying that change twice. Never deduplicate on signature: it changes per attempt.event.created y event.updated incluyen event_id; order.completed y order.refunded incluyen order_id y resource_type. Consulta el recurso con tu clave para obtener su estado actual. checkin.scanned incluye checkin_id, ticket_id, event_id, direction y scanned_at. Los avisos no contienen emails del comprador.
5. Límites y errores
120 peticiones/minuto por cuenta, compartidas entre claves, y 300/minuto por IP. Un 429 incluye Retry-After. Reintenta 429 y 503 con espera creciente. No reintentes escrituras sin conservar Idempotency-Key. Los errores llevan error.code, error.message y request_id; todas las respuestas incluyen X-Request-Id.
400: parámetros inválidos. 401: clave inválida, caducada, revocada o acceso suspendido. 403: falta un permiso. 404: recurso inexistente o de otra cuenta. 409: conflicto de idempotencia, sesión caducada o venta no disponible. 503: indisponibilidad temporal.
Recetas para empezar
- Catálogo propio: consulta /events y /events/ID/tiers desde tu servidor; actualiza tu caché con event.created y event.updated.
- CRM: recibe order.completed y consulta los asistentes del evento con una clave que tenga attendees:read. Separa comunicaciones de compra y campañas.
- Contabilidad: escucha compras y devoluciones y sincroniza /orders. Deduplica por ID y revisa los importes acumulados; no son facturas fiscales.
- Accesos: recibe checkin.scanned para actualizar tus estadísticas. El escaneo sigue en las herramientas de acceso de Eventium.