Cliente de TypeScript
El paquete oficial: tipos de todo el contrato, reintentos automáticos y verificación de webhooks, sin dependencias.
Última actualización: 23 de agosto de 2026
@tickeep/client es el cliente oficial. Si trabajas en TypeScript o JavaScript, te ahorra escribir el transporte, los reintentos y la verificación de firmas — y te da los tipos de todo el contrato.
Cero dependencias. Solo usa fetch y crypto.subtle, así que funciona en Node 18+, Deno, Bun, Cloudflare Workers, React Native/Expo y el navegador.
El paquete todavía no está publicado en npm. Si quieres usarlo, escríbenos: te pasamos los fuentes, que son una carpeta de TypeScript sin build ni dependencias, para que la copies a tu proyecto.
Crear el cliente
import { TickeepPartnerClient } from '@tickeep/client'
const tickeep = new TickeepPartnerClient({
apiKey: process.env.TICKEEP_API_KEY!,
})
| Opción | Por defecto | Para qué |
|---|---|---|
apiKey | — | Tu clave. Obligatoria |
baseUrl | https://app.tickeep.com | Solo si te lo indicamos |
fetch | El global | Inyectar el tuyo, útil en tests |
Que el cliente funcione en el navegador no significa que debas usarlo ahí con una clave de API. Una clave en un bundle es una clave pública. Ver autenticación.
Métodos
Catálogo
const { data: venues } = await tickeep.venues()
const { data, hasMore, nextCursor } = await tickeep.events({
venueId, status: 'published', updatedSince, limit: 100, cursor,
})
const evento = await tickeep.event(id)
const fechas = await tickeep.performances({ eventId, venueId, from, to, limit, cursor })
const fecha = await tickeep.performance(id)
const { availability, ticketTypes, capacity, sold, available } =
await tickeep.availability(performanceId)
Venta
const order = await tickeep.createOrder(
{
venueId,
items: [{ ticketTypeId, quantity: 2 }],
customer: { email, name, phone },
channel: 'online', // o 'boxOffice'
invoice: true,
},
crypto.randomUUID(), // Idempotency-Key: obligatoria
)
const pedidos = await tickeep.orders({ venueId, status, email, updatedSince, limit, cursor })
const pedido = await tickeep.order(reference)
const { order, tickets, ticketsStatus } = await tickeep.confirmOrder(reference, {
paymentMethod: 'external', // 'cash' | 'cardTerminal' | 'external'
reference: 'AUT-884213',
})
await tickeep.cancelOrder(reference)
const { url, expiresAt } = await tickeep.paymentLink(reference)
createOrder pide la Idempotency-Key como segundo argumento obligatorio, no como opción. Es a propósito: no se puede olvidar sin que TypeScript proteste.
Entradas y control de acceso
const entradas = await tickeep.tickets({
venueId, performanceId, eventId, orderId, status, limit, cursor,
})
const entrada = await tickeep.ticket(code)
const { result, ticket } = await tickeep.checkIn(code, {
performanceId,
dryRun: false,
token,
})
Asistentes e informes
const personas = await tickeep.attendees({ email, updatedSince, limit, cursor })
const informe = await tickeep.salesReport({ venueId, preset: '30d' })
Errores
import { TickeepError } from '@tickeep/client'
try {
await tickeep.createOrder(input, key)
} catch (err) {
if (err instanceof TickeepError) {
if (err.code === 'sold_out') {
return mostrar('Se han agotado mientras comprabas')
}
console.error(err.code, err.status, err.requestId, err.details)
}
throw err
}
| Propiedad | Qué es |
|---|---|
code | El código estable (sold_out, conflict…). Compáralo con === |
status | El código HTTP |
requestId | Lo primero que te pediremos en un ticket de soporte |
details | El objeto details de la respuesta, si venía |
retryAfter | Segundos a esperar, en un 429 |
reintentable | Si merece la pena reintentar |
Hay un código extra que no existe en el contrato HTTP: network_error, para cuando la petición ni siquiera llegó a salir o el timeout se agotó. Es reintentable.
Reintentos automáticos
El cliente reintenta solo los fallos transitorios —5xx, rate_limited y fallos de red— con dos reintentos por defecto y retroceso exponencial. En un 429 respeta el Retry-After que manda el servidor en vez de aplicar su propio cálculo.
El retroceso lleva algo de aleatoriedad, para que veinte lectores que pierden la red a la vez no vuelvan todos en el mismo instante y monten un pico.
Un 4xx no se reintenta nunca: repetirlo daría el mismo resultado.
El cliente reintenta con la misma Idempotency-Key que le pasaste, que es exactamente lo que hace que un reintento tras un corte de red no cree un segundo pedido. Genera la clave fuera de tu propio bucle de reintentos, no dentro.
El timeout por petición es de 20 segundos.
Verificar webhooks
import { verificarFirmaWebhook } from '@tickeep/client'
const ok = await verificarFirmaWebhook({
rawBody, // OJO: el cuerpo CRUDO
signature: req.headers['tickeep-signature'],
secret: process.env.TICKEEP_WEBHOOK_SECRET!,
toleranceSeconds: 300, // opcional
})
Hace las tres cosas que hay que hacer y que es fácil olvidar: firma el cuerpo exacto, comprueba el timestamp por los dos lados y compara en tiempo constante. Ver webhooks.
Usa WebCrypto, por eso es asíncrona.
Los tipos
import type {
Attendee, Availability, CheckInResult, Order, Page,
Performance, Ticket, TicketType, TickeepEvent, Venue,
} from '@tickeep/client'
TickeepEvent y no Event porque Event ya existe en el DOM, y esa colisión se paga en cada archivo del proyecto.
Los listados devuelven Page<T>:
type Page<T> = { data: T[]; hasMore: boolean; nextCursor: string | null }
La referencia campo a campo está en objetos y tipos.
Recorrer un listado entero
async function* todos<T>(
pedir: (cursor?: string) => Promise<Page<T>>,
): AsyncGenerator<T> {
let cursor: string | undefined
do {
const p = await pedir(cursor)
yield* p.data
cursor = p.nextCursor ?? undefined
} while (cursor)
}
for await (const pedido of todos((c) => tickeep.orders({ venueId, limit: 100, cursor: c }))) {
await procesar(pedido)
}
Si no trabajas en TypeScript
La API es HTTP y JSON, así que no hace falta ningún cliente. Lo que sí conviene reproducir de este, en el lenguaje que uses:
- Reintentar solo los fallos transitorios, con retroceso exponencial y respetando
Retry-After. - Guardar el
X-Request-Idde las respuestas de error. - Generar la
Idempotency-Keyfuera del bucle de reintentos. - Verificar la firma de los webhooks sobre el cuerpo crudo, comprobando el timestamp y comparando en tiempo constante.
Seguir por aquí
Cinco llamadas que van de crear una clave a emitir una entrada de verdad, con el porqué de cada paso.
Todos los objetos que devuelve la API, campo a campo, con sus tipos y sus valores posibles.
Que Tickeep avise a tu servidor cuando pasa algo, en vez de preguntar en bucle. Eventos, firma, reintentos y los tres fallos que se cometen siempre.