/yoMándala en la cabecera Authorization de cada petición. Este endpoint te dice si funciona.
curl https://cards.the-vault.mx/api/v1/yo \
-H "Authorization: Bearer vlt_live_TU_LLAVE"La llave puede
Nunca puede
Lo que necesita quien programa tu punto de venta, en el orden en que lo va a hacer.
Genera tu llave
En Configuración → Conexiones, con un código a tu WhatsApp.

Lee tu inventario
Para saber cómo se llama cada carta aquí y cuántas hay.
Ragavan, Nimble Pilferer
MH2-138-EN-NF-1
Descuenta cada venta
Un movimiento por renglón de tu ticket, y escucha nuestros avisos.
Una por tienda. Se muestra una sola vez: si la pierdes, cámbiala y la anterior deja de funcionar.
/yoMándala en la cabecera Authorization de cada petición. Este endpoint te dice si funciona.
curl https://cards.the-vault.mx/api/v1/yo \
-H "Authorization: Bearer vlt_live_TU_LLAVE"La llave puede
Nunca puede
De 500 en 500 con cursor. Filtra por SKU de BinderPOS o por set y número para saber si tienes una carta.
/inventariocurl "https://cards.the-vault.mx/api/v1/inventario?sku=MH2-138-EN-NF-1" \
-H "Authorization: Bearer vlt_live_TU_LLAVE"Así se lee la respuesta
Ragavan, Nimble Pilferer
MH2-138-EN-NF-1
{
"inventario": [{
"id": "5eed0004-…",
"nombre": "Ragavan, Nimble Pilferer",
"set": "MH2", "numero": "138", "idioma": "en", "foil": false,
"condicion": "Near Mint",
"cantidad": 3, "disponible": 2, "apartada_en_subasta": 1,
"en_custodia": false,
"precio_actual": 1450
}],
"siguiente_cursor": null
}/inventario/{id}Por movimiento, nunca por cantidad final: manda −1 cuando vendes una, no “quedan 2”. Si al mismo tiempo se vende otra en línea, los dos se suman bien.
/movimientoscurl -X POST https://cards.the-vault.mx/api/v1/movimientos \
-H "Authorization: Bearer vlt_live_TU_LLAVE" \
-H "Content-Type: application/json" \
-d '{
"movimientos": [{
"sku": "MH2-138-EN-NF-1",
"delta": -1,
"motivo": "venta_mostrador",
"referencia_externa": "ticket-8812-renglon-1",
"precio_venta": 1400
}]
}'Motivos
Cada movimiento responde
referencia_externa es obligatoria
Usa el id de tu ticket o renglón. Si mandas el mismo dos veces —un reintento—, el segundo responde duplicado y no descuenta.
Si se rechaza, trae el motivo
Hasta 100 movimientos por petición, cada uno entre −100 y 100. Nombra la carta con inventario_id, con sku o con set + numero + idioma + foil + condicion. Solo cartas que ya tienes: las nuevas se dan de alta con el importador de colección.
/movimientos?desde=…Tu historial: lo que mandó tu sistema (origen api) y lo que se hizo en la app (origen app).
Lo que se vendió de tu tienda en línea, para descontarlo en tu sistema. Nunca trae datos del comprador.
/ventas?desde=…desde filtra por la última actualización: una venta que cambió de estado vuelve a salir. El neto es el mismo que ves en tu Saldo.
Ragavan, Nimble Pilferer
MH2-138-EN-NF-1
Estados
/ventas/{id}Registra una URL https pública y te avisamos en menos de un minuto cuando se vende o se cancela una venta tuya.
/webhookscurl -X POST https://cards.the-vault.mx/api/v1/webhooks \
-H "Authorization: Bearer vlt_live_TU_LLAVE" \
-H "Content-Type: application/json" \
-d '{ "url": "https://tu-sistema.mx/boveda/avisos" }'El secreto de firma se muestra una sola vez
Hasta 3 URLs por tienda. Pruébala con POST /webhooks/{id}/probar y apágala con DELETE.
Eventos
POST https://tu-sistema.mx/boveda/avisos
X-Vault-Evento: venta.creada
X-Vault-Entrega: 546d… ← el mismo id si te llega dos veces
X-Vault-Firma: t=1791500000,v1=9f2c…
{ "evento": "venta.creada",
"venta": { "id": "964a…", "sku": "MH2-138-EN-NF-1", "nombre": "Ragavan, Nimble Pilferer", "cantidad": 1 } }Verifica la firma
import crypto from 'node:crypto'
// cuerpoCrudo: el body tal cual llegó (string), ANTES de parsearlo.
function avisoValido(cuerpoCrudo, cabeceraFirma, secreto) {
const { t, v1 } = Object.fromEntries(cabeceraFirma.split(',').map((p) => p.split('=')))
if (Math.abs(Date.now() / 1000 - Number(t)) > 300) return false // viejo: descártalo
const esperada = crypto.createHmac('sha256', secreto).update(`${t}.${cuerpoCrudo}`).digest('hex')
return esperada.length === v1.length &&
crypto.timingSafeEqual(Buffer.from(esperada), Buffer.from(v1))
}Si tu URL falla, reintentamos
Responde con cualquier 2xx en menos de 10 segundos; no seguimos redirecciones. Si se perdió un aviso, GET /ventas?desde= siempre tiene la verdad.
Todo error trae { error: { codigo, mensaje } }. Hasta 120 peticiones por minuto por llave; las listas vienen de 500 en 500.
| Código | Qué pasó |
|---|---|
401 token_invalido | Falta la llave, no existe, o la cambiaste o desconectaste. |
403 solo_tiendas | La cuenta de la llave no es una tienda. |
429 cuota_excedida | Pasaste de 120 peticiones por minuto. Espera lo que diga Retry-After. |
400 lote_invalido | El cuerpo de /movimientos no trae de 1 a 100 movimientos. |
404 no_encontrada | Esa carta o venta no es tuya o no existe. |
500 error_interno | Algo falló de nuestro lado. Reintenta con la misma referencia_externa. |
¿Listo para conectarla?
Genera tu llave y pégala en tu punto de venta.