Ir al contenido principal
Volver a la documentación

API pública Lunidex v1

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.

Claves solo para servidores

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.

Inicio rápido

La integración necesita una clave, un secreto almacenado en el servidor y una solicitud HTTPS a la URL base de la API.

  1. 1

    Crear una clave

    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.

  2. 2

    Guardar el secreto en el servidor

    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.

  3. 3

    Enviar la primera solicitud

    Llama a GET /me desde tu servidor. Las rutas privadas requieren el encabezado Authorization: Bearer seguido de la clave.

cURL · ejecutar en un entorno de servidor de confianza
curl --fail-with-body \
  -H "Authorization: Bearer $LUNIDEX_API_KEY" \
  https://lunidex.app/api/v1/me
Node.js · fetch del lado del servidor
const 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);

Autenticación y permisos

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.

Lectura

Permite llamar a las rutas GET. Elige este permiso si la integración solo necesita mostrar o exportar datos de la cuenta.

Lectura y escritura

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.

Paginación y filtros

Las listas devuelven data y meta.nextCursor. Envía ese cursor sin modificar para solicitar la página siguiente y termina cuando sea null.

  • El tamaño predeterminado es 25 y el máximo 100. El catálogo devuelve como máximo 24 resultados por página.
  • Las cartas aceptan los filtros language y set. Las posiciones selladas aceptan language y productId; las transacciones aceptan language, productId, type, includeVoided y voided. El catálogo acepta q y cursor.
  • El cursor puede quedar obsoleto si cambian la colección, el registro, los precios o los filtros. La API devuelve 409; vuelve a empezar sin cursor con el estado más reciente.
Leer todas las páginas de cartas desde un servidor
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);

Rutas

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.

Cuenta y contrato

  • GETPública · sin clave
    /openapi.json

    Contrato legible por máquinas, público y sin clave API.

    Parámetros:Ninguno
  • GETClave de solo lectura
    /me

    Identidad limitada de la cuenta, sin correo electrónico.

    Parámetros:Ninguno
  • GETClave de solo lectura
    /summary

    Estadísticas principales, recuento físico y distinto de cartas y totales sellados en céntimos EUR.

    Parámetros:Ninguno

Colección de cartas

  • GETClave de solo lectura
    /cards

    Posesiones paginadas, con filtros opcionales de idioma y set.

    Parámetros:
    • cursor(consulta)
    • limit(consulta)
    • language(consulta)
    • set(consulta)
  • GETClave de solo lectura
    /cards/{cardId}

    Metadatos de TCGdex y posesiones de la cuenta, sin valorar cartas.

    Parámetros:
    • cardId(ruta)· obligatorio
    • language(consulta)
  • PUTClave de lectura y escritura
    /cards/{cardId}

    Establece una cantidad absoluta para una carta, idioma y variante.

    Parámetros:
    • cardId(ruta)· obligatorio

Productos sellados y transacciones

  • GETClave de solo lectura
    /sealed/catalogue

    Busca en el catálogo existente de productos sellados de Cardmarket.

    Parámetros:
    • q(consulta)
    • cursor(consulta)
  • GETClave de solo lectura
    /sealed/positions

    Posiciones actuales paginadas con coste y valor de mercado almacenado.

    Parámetros:
    • cursor(consulta)
    • limit(consulta)
    • language(consulta)
    • productId(consulta)
  • GETClave de solo lectura
    /sealed/positions/{productId}

    Posiciones por idioma para un producto que posee la cuenta.

    Parámetros:
    • productId(ruta)· obligatorio
  • GETClave de solo lectura
    /sealed/transactions

    Registro privado de transacciones con revisiones y filtros.

    Parámetros:
    • cursor(consulta)
    • limit(consulta)
    • language(consulta)
    • productId(consulta)
    • type(consulta)
    • includeVoided(consulta)
    • voided(consulta)
  • POSTClave de lectura y escritura
    /sealed/transactions

    Crea una compra, venta o intercambio; requiere clave de idempotencia.

    Parámetros:
    • Idempotency-Key(encabezado)· obligatorio
  • GETClave de solo lectura
    /sealed/transactions/{id}

    Lee una transacción de esta cuenta.

    Parámetros:
    • id(ruta)· obligatorio
  • PATCHClave de lectura y escritura
    /sealed/transactions/{id}

    Modifica una transacción con control de revisiones.

    Parámetros:
    • id(ruta)· obligatorio
  • POSTClave de lectura y escritura
    /sealed/transactions/{id}/void

    Anula una transacción con control de revisiones.

    Parámetros:
    • id(ruta)· obligatorio

Cartas

GET /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.

PUT /cards/{cardId} · application/json
{
  "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.

Productos sellados

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.

GET /sealed/catalogue

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

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.

GET /sealed/transactions

El registro privado admite los filtros language, productId, type (buy, sell, exchange), includeVoided y voided. Incluye revisiones para permitir cambios seguros.

Escrituras, idempotencia y revisiones

Establecer la cantidad de una carta

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.

Crear una transacción sellada

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.

Ejemplo de cuerpo de compra · sustituye el ID del producto y la revisión por los valores actuales
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.

application/json
{
  "revision": 1,
  "expectedRevision": 0
}

Errores y formato de respuesta

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.

Cuotas

Los límites se aplican por cuenta Lunidex y se comparten entre sus claves API.

Cuotas
Lecturas por minuto60
Escrituras por minuto10
Lecturas por día1000
Escrituras por día100
Detalles de cartas por cuenta y día100
Cálculos de sellados por cuenta y día100
Límite global diario por categoría costosa5000

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