Saltar a la guía
Scholaris

API v1 https://scholaris-v2.jlsf2005.workers.dev/api/v1

Subes cualquier cosa, buscas, preguntas y citas.

Una cabecera, nueve verbos y JSON de ida y vuelta (o Markdown, que los agentes leen mejor). Cada pasaje llega con su página impresa o su segundo exactos y un enlace al lector, y ninguna cita sale de un modelo: todas salen del ancla guardada.

Funciona igual en la nube y en la versión de casa.

Empieza en un minuto

  1. Crea una clave en Ajustes → Claves de API, con los alcances de lectura y escritura. Se enseña una sola vez: guárdala. Crear clave
  2. Sube un fichero. La petición espera a que esté leído (hasta un minuto; si tarda más, responde 202 con dónde preguntar).
  3. Busca. Cada pasaje trae su cita lista para pegar, el localizador exacto y el enlace al lector en esa página.
export SCHOLARIS=sch_…   # tu clave

curl -s https://scholaris-v2.jlsf2005.workers.dev/api/v1/documentos -H "Authorization: Bearer $SCHOLARIS" \
  -H "Content-Type: application/pdf" --data-binary @articulo.pdf

curl -sG https://scholaris-v2.jlsf2005.workers.dev/api/v1/buscar -H "Authorization: Bearer $SCHOLARIS" \
  --data-urlencode "q=atención escalada" -d k=3 -d formato=markdown

Los ejemplos se pueden copiar y pegar tal cual: solo hace falta la variable SCHOLARIS con tu clave.

Los nueve verbos

Todo cuelga de una misma dirección base. Los nombres de los campos están en castellano y en minúsculas.

https://scholaris-v2.jlsf2005.workers.dev/api/v1

POST /api/v1/documentos

Sube cualquier cosa: el fichero como cuerpo (PDF, EPUB, DOCX, presentaciones, hojas, audio, vídeo, imágenes), un formulario multipart con el campo archivo o un JSON con url (una web, un PDF, YouTube, Vimeo, un pódcast). Si el fichero ya estaba (misma huella SHA-256), devuelve el que hay con duplicado.

# Un fichero, como cuerpo (con su tipo y su nombre)
curl -s "https://scholaris-v2.jlsf2005.workers.dev/api/v1/documentos?nombre=libro.epub" -H "Authorization: Bearer $SCHOLARIS" \
  -H "Content-Type: application/epub+zip" --data-binary @libro.epub

# Una URL (web, PDF, YouTube, Vimeo, pódcast), sin esperar
curl -s "https://scholaris-v2.jlsf2005.workers.dev/api/v1/documentos?esperar=0" -H "Authorization: Bearer $SCHOLARIS" \
  -H "Content-Type: application/json" -d '{"url": "https://www.youtube.com/watch?v=fNk_zzaMoSs"}'

# Un formulario, con la ficha
curl -s https://scholaris-v2.jlsf2005.workers.dev/api/v1/documentos -H "Authorization: Bearer $SCHOLARIS" \
  -F archivo=@entrevista.mp3 -F titulo="A fondo" -F autores="Cortázar, Julio" -F anio=1977

GET /api/v1/documentos

Lista la biblioteca. Filtra con q (título o autor) y estado; pagina con cursor.

curl -sG https://scholaris-v2.jlsf2005.workers.dev/api/v1/documentos -H "Authorization: Bearer $SCHOLARIS" -d estado=listo -d formato=markdown

GET /api/v1/documentos/{id}

La ficha: título, autores, año, estado, progreso mientras se procesa y la referencia completa cuando está listo. Con esperar=30 espera a que termine.

curl -s "https://scholaris-v2.jlsf2005.workers.dev/api/v1/documentos/ID?esperar=30" -H "Authorization: Bearer $SCHOLARIS"

DELETE /api/v1/documentos/{id}

Lo borra con todo lo derivado (páginas, vectores, imágenes).

curl -s -X DELETE https://scholaris-v2.jlsf2005.workers.dev/api/v1/documentos/ID -H "Authorization: Bearer $SCHOLARIS"

GET /api/v1/documentos/{id}/texto

Lee el texto por páginas o por un tramo de tiempo. desde y hasta admiten el folio impreso (23, xiv), la posición física entre corchetes ([12]) y, en audio y vídeo, tiempos (1:06:56).

# Las páginas 23 a 25 tal como están impresas
curl -sG https://scholaris-v2.jlsf2005.workers.dev/api/v1/documentos/ID/texto -H "Authorization: Bearer $SCHOLARIS" -d desde=23 -d hasta=25 -d formato=markdown

# Un tramo de una entrevista
curl -sG https://scholaris-v2.jlsf2005.workers.dev/api/v1/documentos/ID/texto -H "Authorization: Bearer $SCHOLARIS" -d desde=1:06:00 -d hasta=1:08:00

GET /api/v1/buscar

Busca pasajes (búsqueda híbrida y reordenada). Entre comillas, una frase literal. Cada pasaje trae cita, localizador, ancla, enlace y el texto literal.

curl -sG https://scholaris-v2.jlsf2005.workers.dev/api/v1/buscar -H "Authorization: Bearer $SCHOLARIS" \
  --data-urlencode "q=la música me metía en el tiempo" -d k=5

POST /api/v1/preguntar

Responde en Markdown con notas al pie [^n]. El redactor solo puede citar los pasajes que se le dan, y cada nota se comprueba. Con stream llega por eventos.

curl -s https://scholaris-v2.jlsf2005.workers.dev/api/v1/preguntar -H "Authorization: Bearer $SCHOLARIS" -H "Content-Type: application/json" \
  -d '{"pregunta": "¿Qué le pasa a Johnny con el tiempo cuando toca?"}'

POST /api/v1/citar

Devuelve tu texto con las citas insertadas (página exacta y cualquier estilo CSL) y la bibliografía. También acepta un .docx y lo devuelve citado, con su formato.

curl -s https://scholaris-v2.jlsf2005.workers.dev/api/v1/citar -H "Authorization: Bearer $SCHOLARIS" -H "Content-Type: application/json" \
  -d '{"texto": "La música no saca a Johnny del tiempo: lo mete en otro.", "estilo": "chicago-author-date"}'

# Un .docx, devuelto citado
curl -s "https://scholaris-v2.jlsf2005.workers.dev/api/v1/citar?estilo=apa" -H "Authorization: Bearer $SCHOLARIS" \
  -H "Content-Type: application/vnd.openxmlformats-officedocument.wordprocessingml.document" \
  -H "Accept: application/vnd.openxmlformats-officedocument.wordprocessingml.document" \
  --data-binary @trabajo.docx -o trabajo-citado.docx

POST /api/v1/verificar

Dice si tu biblioteca respalda una afirmación: respaldada, parcial, sin_respaldo o contradicha, con la probabilidad y los pasajes.

curl -s https://scholaris-v2.jlsf2005.workers.dev/api/v1/verificar -H "Authorization: Bearer $SCHOLARIS" -H "Content-Type: application/json" \
  -d '{"afirmacion": "Johnny Carter dice que la música lo mete en el tiempo."}'

Cualquier lectura admite formato=markdown (o la cabecera Accept: text/markdown).

Lo que tarda (subir y citar) espera por defecto y responde con el resultado. Para no esperar, esperar=0 o la cabecera Prefer: respond-async: la respuesta es un 202 con progreso_url.

Una sesión de verdad

Cinco órdenes grabadas tal cual contra la versión local, con los ficheros del banco de pruebas: un cuento de Cortázar en PDF y una clase en audio ya subida. Las respuestas largas están recortadas donde dice […].

export B=http://localhost:8795/api/v1 SCHOLARIS=sch_…
  1. Subir un PDF y esperar a que esté leído

    curl -s "$B/documentos?esperar=120" \
      -H "Authorization: Bearer $SCHOLARIS" \
      -H "Content-Type: application/pdf" \
      --data-binary @cortazar1959perseguidor.pdf \
      | jq '{id, titulo, autores, estado, unidades, referencia}'
    {
      "id": "dmuwzohwaoqul34wy",
      "titulo": "El perseguidor",
      "autores": [
        "Cortázar, Julio"
      ],
      "estado": "listo",
      "unidades": 37,
      "referencia": "Cortázar, J. (1996). El perseguidor."
    }
  2. Buscar, en Markdown

    curl -sG "$B/buscar" \
      -H "Authorization: Bearer $SCHOLARIS" \
      --data-urlencode "q=la música me metía en el tiempo" -d k=2 -d formato=markdown
    # la música me metía en el tiempo
    
    ## 1. (Cortázar, 1996, p. 5)
    
    *El perseguidor* · p. 5 · [abrir](http://localhost:8795/lector/dmuwzohwaoqul34wy?u=5&f=dmuwzohwaoqul34wy%3At0.8) · `dmuwzohwaoqul34wy:t0.8`
    
    > Vaya si lo he oído; vaya si he tratado de escribirlo bien y verídicamente en mi biografía de Johnny.
    > 
    > —Por eso en casa el tiempo no acababa nunca, sabes. De pelea en pelea, casi sin comer. Y para colmo la religión, ah, eso no te lo puedes imaginar. Cuando el maestro me consiguió un saxo que te hubieras muerto de risa si lo ves, entonces creo que me di cuenta en seguida. La música me sacaba del tiempo, aunque no es más que una manera de decirlo. Si quieres saber lo que realmente siento, yo creo que la música me metía en el tiempo. Pero entonces hay que creer que este tiempo no tiene nada que ver con... bueno, con nosotros, por decirlo así.
    >
    […]
  3. Un pasaje de audio: el localizador es el segundo

    curl -sG "$B/buscar" \
      -H "Authorization: Bearer $SCHOLARIS" \
      --data-urlencode "q=vectors as arrows in space" -d k=1 \
      | jq '.pasajes[0] | {cita, localizador, enlace}'
    {
      "cita": "(3Blue1Brown, s. f., 0:11)",
      "localizador": "0:11",
      "enlace": "http://localhost:8795/lector/dmuwzm8ascxmk4ayv?t=11.3&f=dmuwzm8ascxmk4ayv%3Ac9tp39p"
    }
  4. Preguntar

    curl -s "$B/preguntar?formato=markdown" \
      -H "Authorization: Bearer $SCHOLARIS" \
      -H "Content-Type: application/json" \
      -d '{"pregunta":"¿Qué le pasa a Johnny con el tiempo cuando toca?"}'
    Cuando Johnny toca, experimenta que el tiempo cambia[^1][^2]. Aunque en un principio expresa que «la música me sacaba del tiempo», matiza que en realidad siente que lo «metía en el tiempo», entendiendo que se trata de un tiempo distinto que no tiene que ver con el orden cotidiano[^3]. Niega que se trate de una abstracción; más bien describe que simplemente cambia de lugar, comparando la experiencia con entrar en «un ascensor de tiempo» donde transcurren decenas de pisos en lo que dura una sola frase, mientras asuntos como las hipotecas o la religión dejan de existir para él[^4]. Asimismo, percibe la elasticidad del tiempo mediante la metáfora de una valija en la que, al tocar, es capaz de meter «cientos y cientos de trajes» o «una tienda entera»[^5].
    
    Durante esos momentos musicales, Johnny siente que se abre una puerta y que vuela hacia un estado de seguridad donde queda «sobre todo sin tiempo, sin que después... sin que hubiera después... Por un rato no hubo más que siempre...»[^6]. Sin embargo, esa vivencia dura solo mientras se encuentra sumergido en la música; al dejar de tocar, cae de nuevo «de cabeza» en sí mismo[^6]. Bruno observa que en su ejecución Johnny «siempre está tocando mañana», adelantándose sin esfuerzo al hoy[^3], y viviendo intensamente lo que describe como su «cuarto de hora de minuto y medio», una alteración temporal frente al límite impuesto por los relojes[^1][^7].
    
    [^1]: Cortázar, *El perseguidor* (1996), p. 9.
    [^2]: Cortázar, *El perseguidor* (1996), p. 5.
    [^3]: Cortázar, *El perseguidor* (1996), p. 5.
    [^4]: Cortázar, *El perseguidor* (1996), pp. 5-6.
    [^5]: Cortázar, *El perseguidor* (1996), p. 6.
    [^6]: Cortázar, *El perseguidor* (1996), p. 34.
    [^7]: Cortázar, *El perseguidor* (1996), pp. 16-17.
    
    ---
    
    Fuentes (confianza alta):
    […]
  5. Citar un texto propio

    curl -s "$B/citar?formato=markdown" \
      -H "Authorization: Bearer $SCHOLARIS" \
      -H "Content-Type: application/json" \
      -d '{"texto":"Johnny Carter siente que la música no lo saca del tiempo, sino que lo mete en otro. Ese tiempo no se parece al de los relojes.","estilo":"apa"}'
    Johnny Carter siente que la música no lo saca del tiempo, sino que lo mete en otro (Cortázar, 1996, p. 5). Ese tiempo no se parece al de los relojes (Cortázar, 1996, pp. 8-9).
    
    ## Referencias
    
    - Cortázar, J. (1996). El perseguidor.

Desde JavaScript

Con fetch y nada más (Node 20 o el navegador). Diez líneas: subir, buscar y preguntar.

import { readFile } from 'node:fs/promises';
const B = 'https://scholaris-v2.jlsf2005.workers.dev/api/v1';
const h = { Authorization: `Bearer ${process.env.SCHOLARIS}` };
const pedir = async (ruta, o = {}) => (await fetch(B + ruta, { ...o, headers: { ...h, ...o.headers } })).json();

const doc = await pedir('/documentos?nombre=articulo.pdf', { method: 'POST', headers: { 'Content-Type': 'application/pdf' }, body: await readFile('articulo.pdf') });
const { pasajes } = await pedir(`/buscar?k=3&q=${encodeURIComponent('atención escalada')}`);
for (const p of pasajes) console.log(p.cita, p.texto.slice(0, 80), p.enlace);
const r = await pedir('/preguntar', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ pregunta: '¿Qué es la atención multicabeza?' }) });
console.log(r.respuesta);

Desde Python

El SDK trae una fachada de cinco verbos sobre esta misma API. Instálalo con pip (solo necesita requests):

pip install scholaris-sdk
from scholaris.api import Scholaris

s = Scholaris("sch_…")                      # o la variable SCHOLARIS_CLAVE
doc = s.subir("articulo.pdf")                # también una URL
for p in s.buscar("atención escalada", k=3):
    print(p["cita"], p["texto"][:80], p["enlace"])
print(s.preguntar("¿Qué es la atención multicabeza?")["respuesta"])
print(s.citar("La atención sustituye a la recurrencia.")["texto"])
print(s.verificar("El Transformer prescinde de la recurrencia.")["veredicto"])

Para agentes

Hay dos caminos: el servidor MCP, para los agentes que hablan MCP, y esta API, que cualquier agente con una herramienta HTTP sabe usar.

En Claude Code, con una clave que tenga el alcance «mcp»:

claude mcp add --transport http scholaris https://scholaris-v2.jlsf2005.workers.dev/mcp \
  --header "Authorization: Bearer sch_…"

En Claude (web o escritorio): Ajustes → Conectores → Añadir conector personalizado, con esta dirección. Inicias sesión en Scholaris y concedes acceso; no hace falta clave.

https://scholaris-v2.jlsf2005.workers.dev/mcp

En Cursor, Windsurf y los demás clientes MCP:

{
  "mcpServers": {
    "scholaris": {
      "url": "https://scholaris-v2.jlsf2005.workers.dev/mcp",
      "headers": { "Authorization": "Bearer sch_…" }
    }
  }
}

Un agente que solo sepa leer la web tiene sus instrucciones en /llms.txt: los verbos, los campos y las reglas para citar sin inventar.

curl -s https://scholaris-v2.jlsf2005.workers.dev/llms.txt
  1. Cita solo lo que devuelve la API, y copia cita y localizador tal cual.
  2. Si citas literalmente, copia el texto literal; si parafraseas, pon igualmente la cita.
  3. Da el enlace: es la manera de comprobar la página o el segundo.
  4. Si la búsqueda no encuentra nada, dilo; no rellenes el hueco de memoria.

Cuando algo falla

Los errores dicen qué ha pasado en castellano («mensaje») y en inglés («message»), con un código estable para el programa y el enlace a esta guía:

{
  "error": {
    "codigo": "prohibido",
    "mensaje": "Esta clave de API es de solo lectura.",
    "message": "This key is not allowed to do that (check its scopes: lectura, escritura, mcp).",
    "estado": 403,
    "documentacion": "https://scholaris-v2.jlsf2005.workers.dev/api#errores"
  }
}
CódigoHTTPQué significa
no_autenticado401Falta la clave, no vale o se ha revocado.
prohibido403La clave no tiene el alcance necesario (escribir necesita escritura).
peticion_invalida400Falta un campo o no es válido: el mensaje dice cuál.
no_encontrado404No existe o no es tuyo.
conflicto409Choca con el estado actual; por ejemplo, el documento aún no tiene texto.
demasiado_grande413Por aquí caben ficheros de hasta 95 MB; para más, el SDK sube por partes.
cuota_superada · requiere_pro402Se ha agotado una cuota del plan.
limite_de_ritmo429Demasiadas peticiones seguidas: espera los segundos de Retry-After.
proveedor_fallo502Ha fallado un proveedor de IA: vuelve a intentarlo.

Los límites de ritmo y las cuotas son los de tu plan, los mismos que en la aplicación.

Para reintentar sin duplicar, manda una cabecera Idempotency-Key en «subir» y «citar»: con la misma clave, durante 24 horas, se devuelve el mismo recurso.

De dónde sale cada cita

Al leer un documento, Scholaris guarda de cada pasaje un ancla: la página física y el folio impreso que se ve en el papel, el segundo de un audio o de un vídeo, la diapositiva, la sección y el párrafo de una web. Es lo que devuelve el campo ancla.

La cita y el localizador se escriben desde esa ancla, nunca desde lo que diga un modelo; el enlace abre el lector en esa misma página o en ese mismo segundo. Si un pasaje no está en tu biblioteca, la API no lo cita.