API v1

Referencia de la API

Lectura abierta, escritura con sesión GitHub o token ih_…. Todas las respuestas usan el envelope {success, data?, error?}.

01Base y autenticación

Base:  https://indexlyhub.daida.net/api/v1
Auth:  Authorization: Bearer <jwt-sesion>   (web, tras login GitHub)
       Authorization: Bearer ih_<secreto>    (token personal, perfil → Tokens)

Los tokens tienen scopes: read (defecto) y write (publicar, actualizar, borrar, favoritos, reportes). Crear tokens exige sesión web; el secreto se muestra una sola vez. Si se expone, revócalo en tu perfil.

curl "https://indexlyhub.daida.net/api/v1/packages?q=steam&sort=downloads&pageSize=5"

curl -H "Authorization: Bearer ih_TUSECRETO" \
  -H "Content-Type: application/json" \
  -d '{"name":"Mi paquete","data":{"items":[{"title":"A","url":"https://…"}]}}' \
  https://indexlyhub.daida.net/api/v1/packages

02Playground

Prueba los endpoints de lectura sin salir de aquí. Para los que piden auth, pega tu sesión o token (se queda en tu navegador).

// pulsa Ejecutar…

03Paquetes

GET/packages

Lista paginada. Params: q (máx 200), tag, tags (coma), author (login o id), sort (recent · downloads · name-asc · name-desc · items-desc), page, pageSize (máx 100). Responde data[] + meta{total,page,pageSize,hasMore}.

GET/packages/{slug}

Metadatos + r2Url del fichero.

GET/packages/{slug}/file

JSON con r2_url. Con ?redirect=1 cuenta la descarga y redirige 302 al CDN.

POST/packages/{slug}/download

Cuenta una descarga/importación sin descargar el fichero.

GET/packages/{slug}/raw

Contenido: r2_url (filas R2, descarga del CDN) o rawData inline (legacy).

POST/packagesauth write

JSON {name, slug?, description?, tags?, version?, mapping?, data} o FormData. El servidor recalcula checksum/tamaño/items y aplica cuotas (5 MB/archivo, 50 MB y 30 paquetes/usuario, 10 subidas/hora, dedup SHA-256). → 201.

PUT/packages/{slug}owner/admin

Campos parciales + data opcional (sustituye fichero con key versionada). 409 si no hay cambios.

DELETE/packages/{slug}owner/admin

Borra fila + fichero R2.

04Descubrir

GET/stats

{totalPackages, totalItems, totalDownloads, topTags, generatedAt}.

GET/tags?limit=12

Top tags con conteo.

GET/feed

Señal de frescura {maxUpdatedAt, total} para invalidar cachés (la web la consulta cada 5 min).

05Favoritos auth

GET/favorites

Los tuyos, recientes primero.

POST/favorites

{package_slug, item_title, item_link, item_data?}201 (409 si ya estaba).

DELETE/favorites?item_link=…

Quitar (también acepta JSON con item_link).

GET/favorites/check?item_link=…

{favorited: boolean}.

06Tokens auth

GET/tokens

Lista (nombre, prefijo, scopes, usos, expiración). Nunca devuelve secretos.

POST/tokens

{name, scopes?([read]|[read,write]), expiresInDays?}. Solo desde sesión web, máx 20 activos. El token vuelve una vez.

DELETE/tokens/{id}

Revoca (borrado lógico).

# ejemplo CI: publicar cada noche
TOKEN=$(curl -s -H "Authorization: Bearer $SESSION_JWT" \
  -H "Content-Type: application/json" \
  -d '{"name":"nightly","scopes":["read","write"],"expiresInDays":90}' \
  https://indexlyhub.daida.net/api/v1/tokens | python3 -c "import sys,json;print(json.load(sys.stdin)['data']['token'])")

07Reportes

POST/reportsauth write

{slug, reason (máx 120), details? (máx 2000)}201.

GET/reports?status=openadmin

Cola de moderación.

08Errores y límites

Todo error responde {success:false, error:{code,message,details?}} con su HTTP:

HTTPcodeCuándo
400VALIDATION_ERRORParámetros o JSON inválidos (details por campo)
401UNAUTHORIZEDFalta Bearer o sesión/token inválido/revocado
403FORBIDDENSin scope write, sin permiso o cuota llena
404NOT_FOUNDSlug inexistente
409CONFLICTSlug o checksum duplicado · sin cambios
413FILE_TOO_LARGE> 5 MB comprimido
429RATE_LIMITED300 lecturas/min · 60 escrituras/min · 10 subidas/hora (cabeceras RateLimit-* + Retry-After)
500STORAGE_ERROR/INTERNAL_ERRORR2 o Supabase no disponible

09Changelog

  • v1.0 — API v1: lecturas abiertas, escritura con sesión/token, tokens ih_…, favoritos y reportes vía API, rate limits, openapi.json.

← Guías · openapi.json