Una API a la altura de tu producto
Eventos, sesiones, entradas, pedidos, accesos, clientes y devoluciones por API REST, con la misma lógica que el panel. Versionada por fecha, idempotente y con webhooks firmados.
- Versión actual
- 2026-10-01
- Formato
- REST · JSON · UTF-8
- Alojamiento
- Servidores en la UE
- Autenticación
- Bearer · claves restringidas
curl https://api.addon-ticket.com/v1/orders \
-H "Authorization: Bearer sk_test_7Qp2…" \
-H "AddOnTicket-Version: 2026-10-01" \
-H "Idempotency-Key: 5f1c2a9e-checkout-8841" \
-H "Content-Type: application/json" \
-d '{
"session": "ses_0199c2a4e1b37d40a6f2c9e15b7d3a08",
"items": [{ "ticket_type": "tt_0199c2a4e1b37d40a6f2c9e15b7d3a11", "quantity": 2 }],
"customer": { "name": "Lucía Ortega", "email": "lucia@example.com" },
"payment_mode": "checkout_link"
}'const res = await fetch("https://api.addon-ticket.com/v1/orders", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.ADDON_TICKET_KEY}`,
"AddOnTicket-Version": "2026-10-01",
"Idempotency-Key": "5f1c2a9e-checkout-8841",
"Content-Type": "application/json",
},
body: JSON.stringify({
session: "ses_0199c2a4e1b37d40a6f2c9e15b7d3a08",
items: [{ ticket_type: "tt_0199c2a4e1b37d40a6f2c9e15b7d3a11", quantity: 2 }],
customer: { name: "Lucía Ortega", email: "lucia@example.com" },
payment_mode: "checkout_link",
}),
});
const order = await res.json();
if (!res.ok) throw new Error(order.error.code);
console.log(order.payment_url);<?php
$ch = curl_init('https://api.addon-ticket.com/v1/orders');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('ADDON_TICKET_KEY'),
'AddOnTicket-Version: 2026-10-01',
'Idempotency-Key: 5f1c2a9e-checkout-8841',
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode([
'session' => 'ses_0199c2a4e1b37d40a6f2c9e15b7d3a08',
'items' => [['ticket_type' => 'tt_0199c2a4e1b37d40a6f2c9e15b7d3a11', 'quantity' => 2]],
'customer' => ['name' => 'Lucía Ortega', 'email' => 'lucia@example.com'],
'payment_mode' => 'checkout_link',
]),
]);
$order = json_decode(curl_exec($ch), true);
echo $order['payment_url'];import os, requests
r = requests.post(
"https://api.addon-ticket.com/v1/orders",
headers={
"Authorization": f"Bearer {os.environ['ADDON_TICKET_KEY']}",
"AddOnTicket-Version": "2026-10-01",
"Idempotency-Key": "5f1c2a9e-checkout-8841",
},
json={
"session": "ses_0199c2a4e1b37d40a6f2c9e15b7d3a08",
"items": [{"ticket_type": "tt_0199c2a4e1b37d40a6f2c9e15b7d3a11", "quantity": 2}],
"customer": {"name": "Lucía Ortega", "email": "lucia@example.com"},
"payment_mode": "checkout_link",
},
)
order = r.json()
print(order["payment_url"]){
"id": "ord_0199c2a5f0d47e2b8c1a9e3f5d7b2c64",
"object": "order",
"number": "AOT-7Q4M-2K",
"status": "pending_payment",
"event": "evt_0199c2a4e1b37d40a6f2c9e15b7d39f2",
"session": "ses_0199c2a4e1b37d40a6f2c9e15b7d3a08",
"channel": "api",
"buyer": { "name": "Lucía Ortega", "email": "lucia@example.com", "phone": null },
"amount_subtotal": 7800,
"amount_fees": 606,
"amount_total": 8406,
"currency": "EUR",
"payment_url": "https://api.addon-ticket.com/pay/…",
"expires_at": "2026-10-01T10:10:00Z",
"tickets": [],
"livemode": false
}Aburrida en lo que importa
Las decisiones de diseño que hacen que una integración funcione el día del estreno igual que el día que la escribiste.
REST y JSON predecibles
Recursos en plural, verbos HTTP de siempre e identificadores con prefijo legible. Si sabes leer una URL, sabes usar la API.
GET /v1/tickets/tkt_k3m9q2x7abVersionado por fecha
Tu integración queda fijada en la versión con la que empezaste. Los cambios incompatibles solo llegan cuando tú cambias la cabecera.
AddOnTicket-Version: 2026-10-01Claves de prueba y de producción
Mismo código, dos mundos separados: las claves de prueba solo ven eventos de prueba y cobran en sandbox. Cada clave lleva solo los permisos que necesita.
sk_test_… · sk_live_…Idempotencia
Reintenta sin miedo: con la misma clave durante 24 h devolvemos la misma respuesta y nunca cobramos dos veces.
Idempotency-Key: 5f1c2a9e-checkout-8841Paginación por cursor
Listas estables aunque entren pedidos mientras paginas. Hasta 100 elementos por página, has_more y next_cursor.
?limit=100&starting_after=ord_0199c2a5f0d4…Errores tipados
Cada error trae tipo, código estable, mensaje en español, el parámetro que lo provocó y el Request-Id para que lo busquemos contigo.
{ "type": "permission_error", "code": "insufficient_scope" }Límites claros
100 peticiones por segundo por clave real y 25 en pruebas, con cabeceras RateLimit-* y Retry-After. ¿Una salida a la venta enorme? Lo ampliamos.
429 · rate_limit_error · Retry-After: 1Un error, tal y como te llega:
{
"error": {
"type": "invalid_request_error",
"code": "ticket_type_sold_out",
"message": "No quedan entradas suficientes",
"param": null,
"doc_url": "…/desarrolladores#errores-ticket_type_sold_out",
"request_id": "req_8Yk2pQm1…"
}
}Once recursos. Todo el ciclo de una entrada.
Del evento a la puerta y a la devolución. Ids con prefijo (evt_, ses_, tt_, ord_, tkt_), importes en céntimos y fechas en UTC.
https://api.addon-ticket.com/v1
- events
Crea, edita y publica eventos. Con una clave de pruebas nacen como eventos de prueba.
GETPOSTPATCH/v1/events - sessions
Fechas de cada evento: horario, puertas, aforo y ventana de venta.
GETPOSTPATCH/v1/events/{id}/sessions - ticket_types
Precios, cupos, canales de venta y verificación requerida.
GETPOSTPATCH/v1/events/{id}/ticket_types - availability
Aforo, vendidas, retenidas y libres por tipo de entrada y butaca.
GET/v1/sessions/{id}/availability - orders
Pedidos de servidor a servidor: con enlace de pago o cobrados fuera (taquilla, B2B).
GETPOST/v1/orders - tickets
Entradas emitidas por pedido, sesión o evento, con titular, estado y acceso.
GET/v1/tickets - checkins
Valida un QR o un tkt_ desde tornos y controles de terceros.
POST/v1/checkins - customers
Compradores de tu organización, consentimiento e historial de gasto.
GET/v1/customers - refunds
Devoluciones totales, por entradas o por importe, con la misma lógica que el panel.
GETPOST/v1/refunds - reports
Ventas por día: pedidos, entradas, importe, comisiones y devoluciones.
GET/v1/reports/sales - webhooks
Suscripciones por tipo de evento, prueba de envío y rotación del secreto.
GETPOSTPATCHDELETE/v1/webhook_endpoints Especificación OpenAPI 3.1 en /v1/openapi.json y referencia navegable en /v1/docs: genera tu cliente o impórtala en tu herramienta.
Te avisamos antes de que preguntes
Eventos firmados con HMAC-SHA256 en la cabecera AOT-Signature y reintentados durante 72 horas con espera exponencial. Cada entrega queda registrada y puedes reenviarla desde el panel.
Pedidos y entradas
order.paidPedido pagado (o confirmado sin cobro)order.refundedDevolución total o parcialticket.issuedEntrada emitida, una por plazaticket.transferredLa entrada cambió de titularticket.checked_inEntrada leída en una puerta de entrada
Eventos y dinero
event.publishedEvento publicado y a la ventasession.cancelledSesión canceladapayout.paidCobro ingresado en tu cuenta
Verificación
verification.completedDNI, edad o descuento comprobados con IA
import { createHmac, timingSafeEqual } from "node:crypto";
// AOT-Signature: t=1759312800,v1=9c1f0e… (dos v1 mientras rotas el secreto)
export function verify(rawBody: string, header: string, secret: string) {
const parts = header.split(",").map((p) => p.split("="));
const t = Number(parts.find(([k]) => k === "t")?.[1]);
if (!t || Math.abs(Date.now() / 1000 - t) > 300) return false; // 5 min
const expected = createHmac("sha256", secret)
.update(`${t}.${rawBody}`)
.digest();
return parts
.filter(([k]) => k === "v1")
.some(([, v]) => {
const got = Buffer.from(v, "hex");
return got.length === expected.length && timingSafeEqual(got, expected);
});
}Comprueba siempre la firma sobre el cuerpo sin procesar y rechaza marcas de tiempo de más de 5 minutos: así evitas repeticiones aunque alguien intercepte una petición.
Tu lenguaje, con la especificación oficial
La especificación OpenAPI 3.1 está publicada: genera un cliente tipado para tu lenguaje con las herramientas de siempre. El entorno de pruebas funciona igual que producción.
TypeScript / Node
$ npx openapi-typescript https://api.addon-ticket.com/v1/openapi.json -o addon-ticket.d.tsPHP 8.2+
$ npx @openapitools/openapi-generator-cli generate -g php -i https://api.addon-ticket.com/v1/openapi.json -o addon-ticket-phpPython 3.10+
$ npx @openapitools/openapi-generator-cli generate -g python -i https://api.addon-ticket.com/v1/openapi.json -o addon_ticketWebhooks de prueba desde el panel
En Desarrolladores › Webhooks envías un evento de prueba a tu endpoint, ves cada entrega con su respuesta y tiempo, y reenvías las que fallaron.
Enviar prueba → https://tu-web.es/webhooks
→ 200 ping 41 ms
→ 500 order.paid reintento 2/8 · ReenviarEntorno de pruebas
Con una clave sk_test_ todo va a eventos de prueba aislados: no salen en la web, el pago es una pasarela simulada y los webhooks van a tus endpoints de prueba. Sin coste.
payment_mode: checkout_link → sandbox
Vende en tu web con una línea
Una línea de HTML: un botón que abre la compra sobre tu web o la compra incrustada con altura automática. Al terminar, tu página recibe el evento aot:purchase. Pesa menos de 15 KB.
<script src="https://addon-ticket.com/widget.js"
data-event="sala-sur/sur-fest-2026" async></script>
<script>
document.addEventListener("aot:purchase", (e) => {
console.log("Pedido", e.detail.number);
});
</script>- Botón de compra
- Compra incrustada
- Evento aot:purchase
- Dominios permitidos por organización
Sáb 14 nov · Sevilla
Sur Fest 2026
Anticipada
Agotada
General
39,00 €
VIP con zona lounge
89,00 €
Vista previa ilustrativa del widget
Transparencia, también cuando algo falla
Publicamos cada incidencia con su causa y su duración. Infraestructura propia en servidores de la UE: Postgres, Node y Valkey, sin depender de terceros para servir tus entradas.
Todos los sistemas operativos
Ejemplo ilustrativo- API99,99 %
- Pagos y cobros100 %
- Webhooks99,97 %
- App de acceso100 %
- Verificaciones con IA99,95 %
Tu primera entrada por API, hoy
Crea una cuenta de pruebas, copia tu clave sk_test_ y emite una entrada real en tu móvil en menos de diez minutos.