Lectura
Permite llamar a las rutas GET. Elige este permiso si la integración solo necesita mostrar o exportar datos de la cuenta.
Conecta una integración de servidor con los datos ya sincronizados en una cuenta Lunidex. Crea una clave y envía una primera solicitud; después explora cartas, productos sellados, paginación y escrituras seguras.
Nunca pongas una clave API en código del navegador, una aplicación móvil, un repositorio público, una URL, una captura de pantalla o un registro compartido. Guárdala en un gestor de secretos del servidor y envíala solo en el encabezado Authorization.
La integración necesita una clave, un secreto almacenado en el servidor y una solicitud HTTPS a la URL base de la API.
Abre la tarjeta de claves API en el panel de Lunidex. Asigna un nombre y elige solo lectura o lectura y escritura. El secreto completo se muestra una sola vez; cópialo antes de cerrar el aviso.
Guarda la clave como LUNIDEX_API_KEY en el gestor de secretos de tu proveedor de alojamiento. No la incluyas en el repositorio ni la envíes al navegador.
Llama a GET /me desde tu servidor. Las rutas privadas requieren el encabezado Authorization: Bearer seguido de la clave.
curl --fail-with-body \
-H "Authorization: Bearer $LUNIDEX_API_KEY" \
https://lunidex.app/api/v1/meconst API_BASE_URL = "https://lunidex.app/api/v1";
const apiKey = process.env.LUNIDEX_API_KEY;
if (!apiKey) throw new Error("Missing LUNIDEX_API_KEY");
const response = await fetch(API_BASE_URL + "/me", {
headers: { Authorization: "Bearer " + apiKey },
});
const result = await response.json();
if (!response.ok) {
throw new Error(result.error?.code ?? "REQUEST_FAILED");
}
console.log(result.data);Envía la clave en el encabezado HTTP Authorization para cada solicitud privada /api/v1. La API responde con JSON dentro de data; las respuestas privadas usan Cache-Control: private, no-store.
Permite llamar a las rutas GET. Elige este permiso si la integración solo necesita mostrar o exportar datos de la cuenta.
Permite llamar tanto a rutas GET como a las rutas de escritura. Úsalo solo para una integración de servidor de confianza que deba modificar la colección o el registro de productos sellados.
La API solo ve los datos sincronizados con la cuenta Lunidex en Neon. Los datos que solo existen en un dispositivo no están disponibles. La identidad de la cuenta no incluye el correo electrónico.
Las listas devuelven data y meta.nextCursor. Envía ese cursor sin modificar para solicitar la página siguiente y termina cuando sea null.
const API_BASE_URL = "https://lunidex.app/api/v1";
const apiKey = process.env.LUNIDEX_API_KEY;
let cursor = null;
if (!apiKey) throw new Error("Missing LUNIDEX_API_KEY");
do {
const query = new URLSearchParams({ limit: "100" });
if (cursor) query.set("cursor", cursor);
const response = await fetch(API_BASE_URL + "/cards?" + query, {
headers: { Authorization: "Bearer " + apiKey },
});
const result = await response.json();
if (!response.ok) throw new Error(result.error?.code ?? "REQUEST_FAILED");
console.log(result.data);
cursor = result.meta?.nextCursor ?? null;
} while (cursor);Las rutas son relativas a la URL base de la API. Cada fila muestra el acceso requerido y los parámetros del contrato OpenAPI. La especificación legible por máquinas incluye los esquemas completos, ejemplos de solicitud y respuesta, y errores por operación; las secciones siguientes explican los flujos principales.
/openapi.jsonContrato legible por máquinas, público y sin clave API.
/meIdentidad limitada de la cuenta, sin correo electrónico.
/summaryEstadísticas principales, recuento físico y distinto de cartas y totales sellados en céntimos EUR.
/cardsPosesiones paginadas, con filtros opcionales de idioma y set.
cursor(consulta)limit(consulta)language(consulta)set(consulta)/cards/{cardId}Metadatos de TCGdex y posesiones de la cuenta, sin valorar cartas.
cardId(ruta)· obligatoriolanguage(consulta)/cards/{cardId}Establece una cantidad absoluta para una carta, idioma y variante.
cardId(ruta)· obligatorio/sealed/catalogueBusca en el catálogo existente de productos sellados de Cardmarket.
q(consulta)cursor(consulta)/sealed/positionsPosiciones actuales paginadas con coste y valor de mercado almacenado.
cursor(consulta)limit(consulta)language(consulta)productId(consulta)/sealed/positions/{productId}Posiciones por idioma para un producto que posee la cuenta.
productId(ruta)· obligatorio/sealed/transactionsRegistro privado de transacciones con revisiones y filtros.
cursor(consulta)limit(consulta)language(consulta)productId(consulta)type(consulta)includeVoided(consulta)voided(consulta)/sealed/transactionsCrea una compra, venta o intercambio; requiere clave de idempotencia.
Idempotency-Key(encabezado)· obligatorio/sealed/transactions/{id}Lee una transacción de esta cuenta.
id(ruta)· obligatorio/sealed/transactions/{id}Modifica una transacción con control de revisiones.
id(ruta)· obligatorio/sealed/transactions/{id}/voidAnula una transacción con control de revisiones.
id(ruta)· obligatorioGET /cards enumera las variantes en propiedad sin cargar todo el catálogo de TCGdex. Cada posesión incluye cardId, setId, language, variant y quantity; los filtros opcionales son language y set.
GET /cards/{cardId} devuelve metadatos útiles de TCGdex y las posesiones de esa carta en la cuenta. Añade el parámetro language para limitar las posesiones.
PUT /cards/{cardId} recibe language, variant (unspecified, normal, reverse o holo) y una cantidad absoluta de 0 a 10 000. El valor 0 elimina esa variante.
{
"language": "en",
"variant": "reverse",
"quantity": 2
}Las posesiones antiguas sin idioma siguen disponibles; language puede ser null y pueden aparecer marcadas como legacy.
Esta API nunca devuelve valoraciones de cartas.
Las posiciones incluyen cantidades por idioma, coste y valor actual a partir de los precios ya guardados en Lunidex. Los importes son céntimos enteros de EUR. Si falta el precio, valueCents es null y missingPrice lo indica; el resumen también cuenta missingPrices.
En GET /summary, el valor sellado es null si falta el precio de algún producto en propiedad; missingPrices indica cuántos.
Busca productos ya presentes en el catálogo de Cardmarket con q (hasta 150 caracteres) y cursor. Cada página contiene como máximo 24 productos; usa su ID en las solicitudes posteriores.
GET /sealed/positions admite filtros language y productId. GET /sealed/positions/{productId} devuelve la posición actual de un producto. Estas rutas muestran totales actuales, no una serie completa del historial de precios.
El registro privado admite los filtros language, productId, type (buy, sell, exchange), includeVoided y voided. Incluye revisiones para permitir cambios seguros.
PUT /cards/{cardId} establece la cantidad en lugar de sumar una diferencia. Repetir la misma solicitud conserva la misma cantidad; envía 0 para eliminar la variante. La API valida la carta, el set, el idioma y la variante disponible antes de escribir.
POST /sealed/transactions acepta movimientos buy, sell y exchange. Requiere el encabezado Idempotency-Key (8–200 caracteres) y expectedRevision. Reutiliza la misma clave al reintentar la misma solicitud para evitar crear un segundo movimiento. La primera solicitud crea la transacción; una repetición devuelve el resultado original.
curl --request POST "https://lunidex.app/api/v1/sealed/transactions" \
-H "Authorization: Bearer $LUNIDEX_API_KEY" \
-H "Idempotency-Key: lunidex-import-example-001" \
-H "Content-Type: application/json" \
--data '{
"expectedRevision": 0,
"kind": "buy",
"cardmarketProductId": 12345,
"language": "en",
"date": "2026-09-27",
"quantity": 1,
"unitPriceCents": 2500
}'Antes de escribir, lee la última revisión del registro en los metadatos de GET /sealed/transactions y úsala como expectedRevision. PATCH /sealed/transactions/{id} también requiere la revision de esa transacción. Una revisión obsoleta devuelve 409; vuelve a cargar la transacción y el registro antes de decidir si reintentas.
PATCH /sealed/transactions/{id}
POST /sealed/transactions/{id}/void
POST /sealed/transactions/{id}/void requiere revision y expectedRevision. Crear, modificar y anular reutiliza las validaciones, asignaciones y auditoría de transacciones de Lunidex.
{
"revision": 1,
"expectedRevision": 0
}Las respuestas correctas usan { "data": ..., "meta": ... } (meta es opcional). Los errores usan { "error": { "code": ..., "message": ..., "details": ... } } (details es opcional).
Respuestas habituales: 400 datos de transacción no válidos; 401 clave no válida; 403 permiso insuficiente; 404 recurso inexistente o no poseído; 409 cursor o revisión obsoletos; 410 cuenta en proceso de eliminación; 422 parámetro de consulta o cuerpo no válido; 429 cuota alcanzada; 500 error inesperado del servidor; 502 datos de carta no disponibles; 503 API no disponible.
Ante un 409, vuelve a obtener el recurso actual o reinicia la lista sin cursor. No conviertas un conflicto a ciegas en una nueva transacción.
La respuesta 429 incluye Retry-After. Espera al menos esos segundos antes de volver a intentarlo.
Todas las respuestas privadas usan Cache-Control: private, no-store. El documento OpenAPI público está disponible por separado en /api/v1/openapi.json.
Los límites se aplican por cuenta Lunidex y se comparten entre sus claves API.
| Lecturas por minuto | 60 |
|---|---|
| Escrituras por minuto | 10 |
| Lecturas por día | 1000 |
| Escrituras por día | 100 |
| Detalles de cartas por cuenta y día | 100 |
| Cálculos de sellados por cuenta y día | 100 |
| Límite global diario por categoría costosa | 5000 |
Los detalles de cartas y los cálculos de sellados también tienen límites globales independientes de 5 000 operaciones diarias por categoría. La respuesta 429 incluye Retry-After.
Abrir la especificación OpenAPI