Desarrolladores
Race Dept. en tu sitio.
Un botón, la inscripción dentro de tu página o un link; una API para leer tus eventos, resultados y órdenes, y webhooks para que tu sistema se entere de cada venta. Gratis para todos los organizadores.
Empieza en dos minutos
Tu sitio conserva su diseño; la inscripción, el carrito, el deslinde y el pago corren en Race Dept. Tu página nunca toca datos de tarjetas.
- En tu panel, entra a Configuración › Desarrolladores y agrega tu sitio en Sitios autorizados (por ejemplo
https://tusitio.com). - Ahí mismo elige el evento y copia el código.
- Pégalo en tu página. En tu computadora (
localhost) funciona sin autorizarlo, para que pruebes.
<script src="https://racedept.mx/v1/racedept.js" defer></script> <button data-racedept-evento="tu-organizacion/tu-evento">Inscribirme</button>
Botón
Cualquier botón o link con data-racedept-evento abre la inscripción encima de tu página; en celular, a pantalla completa. Los estilos del botón son los tuyos.
| Atributo | Qué hace |
|---|---|
data-racedept-evento | El evento, como organizacion/evento (lo ves en la dirección de su página en Race Dept.). |
data-racedept-color | Opcional. El color de acento en hexadecimal, por ejemplo #2151FF. |
data-racedept-tienda | En lugar de un evento, tu tienda: data-racedept-tienda="organizacion" data-racedept-modo="ventana". |
Dentro de tu página
La inscripción vive en una sección de tu página y crece con su contenido: categorías, carrito, datos de cada participante, deslinde, pago y confirmación con folio.
<script src="https://racedept.mx/v1/racedept.js" defer></script> <div data-racedept-inscripcion="tu-organizacion/tu-evento"></div> <!-- o tu tienda --> <div data-racedept-tienda="tu-organizacion"></div>
Funciona también en sitios que pintan con JavaScript (React, Vue, Webflow, Wix, Shopify): lo que se agregue después se monta solo.
Link con regreso
Sin código: un link normal a la inscripción. Con regreso, al terminar el corredor ve un botón para volver a tu sitio, con el folio y el estado en la dirección.
https://racedept.mx/tu-organizacion/tu-evento/inscripcion?regreso=https://tusitio.com/gracias → al volver: https://tusitio.com/gracias?folio=ORD-7K2M9Q4P&estado=pagada
La dirección de regreso debe ser de uno de tus sitios autorizados.
Eventos en tu página
El script avisa en el elemento (y en document) lo que pasa adentro:
| Evento | detail |
|---|---|
racedept:completado | { folio, estado, evento, tienda }. estado es pagada, o pendiente_pago si eligió OXXO o transferencia. |
racedept:abierto | Se abrió la ventana. Si tu sitio usa scroll suave (Lenis, Locomotive), páralo aquí y reanúdalo al cerrar. |
racedept:cerrado | Cerró la ventana. |
racedept:paso | { ruta }: avanzó de paso (carrito, datos, pago…). |
racedept:sin-cookies | Su navegador no permite comprar dentro de tu página; se le ofrece seguir en una pestaña nueva. |
<script>
document.addEventListener("racedept:completado", (e) => {
// Confírmalo en tu servidor antes de darlo por pagado (ver abajo)
fetch("/mi-api/confirmar?folio=" + e.detail.folio);
});
// También desde JavaScript:
RaceDept.abrir({ evento: "tu-organizacion/tu-evento", color: "#2151FF", alCompletar: (d) => RaceDept.cerrar() });
RaceDept.montar("#inscripcion", { evento: "tu-organizacion/tu-evento" });
</script>Confirma la orden en tu servidor
Lo que llega al navegador se puede alterar. Antes de dar acceso a algo, consulta la orden desde tu servidor con tu llave secreta; o mejor, usa los webhooks.
curl https://racedept.mx/api/v1/ordenes/ORD-7K2M9Q4P \ -H "Authorization: Bearer rd_sk_live_…"
{
"folio": "ORD-7K2M9Q4P",
"tipo": "inscripcion",
"estado": "pagada",
"metodo": "tarjeta",
"moneda": "MXN",
"subtotal": 120000,
"descuento": 0,
"cupon": null,
"cargoServicio": 8000,
"envio": 0,
"total": 128000,
"comprador": { "nombre": "Ana López", "email": "ana@correo.com" },
"evento": { "slug": "fecha-1-2027", "nombre": "Fecha 1", "fecha": "2027-02-20" },
"inscripciones": [
{ "folio": "ABC-4H8N2C6W", "nombre": "Ana López", "email": "ana@correo.com",
"categoria": "Elite Femenil", "dorsal": 214, "estado": "confirmada" }
],
"productos": [],
"creada": "2027-02-10T18:20:41.000Z",
"pagada": "2027-02-10T18:22:05.000Z"
}Los montos van en centavos de peso mexicano, como en Stripe.
API
Base: https://racedept.mx/api/v1. Manda tu llave en la cabecera Authorization: Bearer <llave>. Las respuestas son JSON; los errores, { error: { codigo, mensaje } }. Hasta 600 llamadas por minuto por llave.
| Llave | Para qué |
|---|---|
rd_pk_… | Publicable. Puede ir en tu página: lee lo que ya es público y solo responde a tus sitios autorizados. |
rd_sk_… | Secreta. Solo desde tu servidor; también lee órdenes e inscripciones. Si se filtra, revócala en el panel. |
| Endpoint | Devuelve |
|---|---|
GET /eventos | Tus eventos públicos: fechas, sede, cartel, precio desde, ventana de venta y sus direcciones. |
GET /eventos/{slug} | El evento con sus categorías (precio vigente y si está agotada), productos y serial. |
GET /eventos/{slug}/resultados | Los resultados, si ya están publicados. |
GET /seriales/{slug}/ranking | La clasificación del serial, general y por categoría. |
GET /ordenes/{folio} | Solo llave secreta. La orden: estado, montos, comprador, inscripciones y productos. |
GET /inscripciones?evento={slug} | Solo llave secreta. Las inscripciones pagadas, de 100 en 100 (pagina, estado). |
Webhooks
Agrega la dirección de tu servidor en Configuración › Desarrolladores › Webhooks. Race Dept. le manda un POST con JSON cada vez que:
| Tipo | Cuándo |
|---|---|
orden.pagada | Una orden quedó pagada (inscripciones o un pedido de la tienda). Trae la orden completa. |
orden.cancelada | Se canceló, o venció sin pagarse en OXXO o transferencia (motivo). |
orden.reembolsada | Se reembolsó en línea, completa o en parte (completo). |
resultados.publicados | Publicaste los resultados de un evento. |
POST https://tusitio.com/webhooks/racedept
RaceDept-Evento: orden.pagada
RaceDept-Entrega: 3c1f…
RaceDept-Firma: t=1802367725,v1=5f2b…
{ "id": "evt_…", "tipo": "orden.pagada", "creado": "2027-02-10T18:22:05.000Z", "datos": { "orden": { … } } }Responde con un código 2xx en menos de 10 segundos. Si no, se reintenta a 1 y 5 minutos, media hora, 2, 6 y 24 horas; puedes reenviar desde el panel. Un mismo aviso puede llegar más de una vez: usa id para no procesarlo dos veces.
Comprueba la firma con el secreto del webhook:
import crypto from "node:crypto";
// cuerpo: el texto tal cual llegó (antes de convertirlo a JSON)
export function firmaValida(cuerpo, cabecera, secreto) {
const p = Object.fromEntries(String(cabecera).split(",").map((x) => x.split("=")));
const esperada = crypto.createHmac("sha256", secreto).update(`${p.t}.${cuerpo}`).digest("hex");
const reciente = Math.abs(Date.now() / 1000 - Number(p.t)) < 300;
return reciente && typeof p.v1 === "string" && p.v1.length === esperada.length &&
crypto.timingSafeEqual(Buffer.from(p.v1), Buffer.from(esperada));
}
// Express
app.post("/webhooks/racedept", express.raw({ type: "application/json" }), (req, res) => {
const cuerpo = req.body.toString();
if (!firmaValida(cuerpo, req.get("RaceDept-Firma"), process.env.RACEDEPT_SECRETO)) return res.sendStatus(400);
const aviso = JSON.parse(cuerpo);
if (aviso.tipo === "orden.pagada") {
// aviso.datos.orden.folio, aviso.datos.orden.inscripciones…
}
res.sendStatus(200);
});Pruebas
En tu computadora todo funciona en localhost sin autorizarlo. Para probar el pago de punta a punta sin cobrar, escríbenos y te damos acceso al ambiente de prueba: carga el script desde su dirección y paga con la tarjeta 4242 4242 4242 4242, cualquier fecha futura y cualquier CVC.
<script src="https://racedept-prueba.vercel.app/v1/racedept.js" defer></script>