Saltar al contenido
Tickeep
Índice de la API

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.

Cómo conseguirlo

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ónPor defectoPara qué
apiKey—Tu clave. Obligatoria
baseUrlhttps://app.tickeep.comSolo si te lo indicamos
fetchEl globalInyectar el tuyo, útil en tests
Solo en el servidor

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

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
}
PropiedadQué es
codeEl código estable (sold_out, conflict…). Compáralo con ===
statusEl código HTTP
requestIdLo primero que te pediremos en un ticket de soporte
detailsEl objeto details de la respuesta, si venía
retryAfterSegundos a esperar, en un 429
reintentableSi 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.

Los reintentos y la idempotencia van juntos

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-Id de las respuestas de error.
  • Generar la Idempotency-Key fuera del bucle de reintentos.
  • Verificar la firma de los webhooks sobre el cuerpo crudo, comprobando el timestamp y comparando en tiempo constante.