20DnD Scribe · API
API DE RESUMOS · V1

Resumos publicados, prontos para integração.

Uma API somente leitura para bots, automações, RAG, LLMs e serviços externos consumirem os resumos que já foram publicados no DnD Scribe — sem liberar áudio, transcrição completa ou material em revisão.

READ ONLY JSON + Markdown API Key 300 req/min OpenAPI 3.1
COMECE AQUI

Quickstart

Receba uma API Key.
Ela é criada no Edit → Integrações e começa com dnd_live_.
Guarde a chave como segredo.
Use variável de ambiente ou secret manager. Não coloque a chave no frontend.
Liste os resumos.
Faça um GET /api/v1/summaries com o header Authorization.
Busque o conteúdo completo.
Use GET /api/v1/summaries/{id} e, se quiser, peça text/markdown.
curl \
  -H "Authorization: Bearer $DND_SCRIBE_API_KEY" \
  https://dnd.faysk.dev/api/v1/summaries
ACESSO

Autenticação

Cada chave pertence a uma única campanha. A API não recebe campaignSlug na rota externa: o escopo da campanha é resolvido pela própria credencial.

Escopo disponível na v1: summaries:read. Ele não dá acesso a áudio, ZIPs, transcrições ou ferramentas administrativas.
Authorization: Bearer dnd_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

A chave completa é exibida somente na criação ou rotação. O servidor armazena apenas um hash SHA-256 e um prefixo de identificação.

CONTRATO

Endpoints

GET/api/v1/health

Health check público. Não valida uma API Key específica.

{
  "status": "ok",
  "apiVersion": "v1",
  "service": "DnD Scribe Summary API",
  "documentation": "https://dnd.faysk.dev/docs/api"
}
GET/api/v1/summaries

Lista resumos publicados. A listagem é leve: retorna a descrição curta e metadados, sem o Markdown completo.

ParâmetroUso
limit1–100, padrão 50.
cursorCursor opaco retornado por pagination.nextCursor.
updatedAfterISO 8601; útil para sincronização incremental.
fromData mínima da sessão, inclusiva, em YYYY-MM-DD.
toData máxima da sessão, inclusiva, em YYYY-MM-DD.
arcNome exato do arco, sem diferenciar maiúsculas/minúsculas.
{
  "object": "list",
  "apiVersion": "v1",
  "data": [
    {
      "id": "Svz6mvN0cBUk",
      "title": "Sessão de 15 de agosto de 2026",
      "sessionDate": "2026-08-15",
      "arc": "Castelo em outro plano",
      "summary": "O grupo atravessou o portal...",
      "updatedAt": "2026-08-16T19:30:00.000Z",
      "webUrl": "https://dnd.faysk.dev/#/sessao/Svz6mvN0cBUk/resumo"
    }
  ],
  "pagination": { "limit": 50, "hasMore": false, "nextCursor": null }
}
GET/api/v1/summaries/{id}

Retorna o resumo completo de uma sessão publicada.

{
  "object": "session_summary",
  "apiVersion": "v1",
  "data": {
    "id": "Svz6mvN0cBUk",
    "title": "Sessão de 15 de agosto de 2026",
    "sessionDate": "2026-08-15",
    "arc": "Castelo em outro plano",
    "summary": "Descrição curta do card.",
    "summaryMarkdown": "# Sessão...\n\n## O portal\n\n...",
    "updatedAt": "2026-08-16T19:30:00.000Z",
    "webUrl": "https://dnd.faysk.dev/#/sessao/Svz6mvN0cBUk/resumo",
    "coverImageUrl": "https://...",
    "heroImageUrl": "https://..."
  }
}

Markdown puro

No endpoint de detalhe, envie Accept: text/markdown para receber somente o Markdown publicado.

curl \
  -H "Authorization: Bearer $DND_SCRIBE_API_KEY" \
  -H "Accept: text/markdown" \
  https://dnd.faysk.dev/api/v1/summaries/Svz6mvN0cBUk
LISTAGENS LONGAS

Paginação por cursor

Quando pagination.hasMore for true, envie exatamente o valor de pagination.nextCursor na próxima chamada. O cursor é opaco: não dependa do conteúdo interno.

GET /api/v1/summaries?limit=50
GET /api/v1/summaries?limit=50&cursor=<nextCursor>

A ordenação é por updatedAt DESC e depois id DESC.

POLLING EFICIENTE

Sincronização incremental

Guarde o instante da última sincronização concluída e use updatedAfter para pedir somente registros alterados desde então.

GET /api/v1/summaries?updatedAfter=2026-08-16T19:30:00.000Z
Só avance seu checkpoint depois de percorrer todas as páginas com sucesso. Assim uma falha no meio da sincronização não faz você perder alterações.
MENOS TRÁFEGO

ETag e cache condicional

Listagens e detalhes enviam ETag. Reenvie o valor em If-None-Match. Se a representação não mudou, a resposta será 304 Not Modified, sem corpo.

If-None-Match: "sum-fAbC123..."

O detalhe também envia Last-Modified.

PROTEÇÃO

Rate limit

O limite atual é 300 requisições por minuto por API Key.

X-RateLimit-Limit: 300
X-RateLimit-Remaining: 294
X-RateLimit-Reset: 1786914000

Ao exceder o limite, a API responde 429 e inclui Retry-After. Respeite esse header e use backoff.

FALHAS PREVISÍVEIS

Formato de erros

{
  "error": {
    "code": "invalid_api_key",
    "message": "API key invalida, expirada ou revogada."
  }
}
HTTPCódigo típicoSignificado
400invalid_cursorParâmetro inválido.
401invalid_api_keyChave ausente, inválida, expirada ou revogada.
403insufficient_scopeEscopo necessário não está na chave.
404summary_not_foundResumo publicado não encontrado.
406not_acceptableFormato solicitado não é aceito naquele endpoint.
429rate_limit_exceededLimite por minuto excedido.
500internal_errorFalha inesperada.

Use o status HTTP e error.code para lógica. O texto de message pode evoluir.

CÓDIGO

Exemplos de consumo

Node.js

const apiKey = process.env.DND_SCRIBE_API_KEY;
const response = await fetch('https://dnd.faysk.dev/api/v1/summaries?limit=20', {
  headers: { Authorization: `Bearer ${apiKey}` }
});
if (!response.ok) throw new Error(`HTTP ${response.status}`);
const payload = await response.json();
console.log(payload.data);

Python

import os, requests

response = requests.get(
    "https://dnd.faysk.dev/api/v1/summaries",
    headers={"Authorization": f"Bearer {os.environ['DND_SCRIBE_API_KEY']}"},
    params={"limit": 50},
    timeout=30,
)
response.raise_for_status()
print(response.json()["data"])

RAG / LLM

Use a listagem para descobrir documentos e o detalhe com Accept: text/markdown para obter o corpo a ser indexado. Armazene id, updatedAt, sessionDate, arc e webUrl como metadados.

SEGURANÇA

O que é e o que não é exposto

A API só devolve sessões com status published e resumo completo não vazio, dentro da campanha da chave.

Não são expostos: áudio, ZIPs, arquivos locais, transcrição completa, falas individuais, drafts, sessões em processamento, material de revisão ou dados de outra campanha.

Chaves podem ser revogadas ou rotacionadas em Edit → Integrações. A chave antiga é invalidada imediatamente na rotação.

COMPATIBILIDADE

Versionamento

O contrato externo vive em /api/v1/.... Dentro da v1 podemos adicionar campos sem remover os existentes. Consumidores devem ignorar propriedades desconhecidas e nunca interpretar o cursor.

Uma mudança incompatível será publicada em uma nova versão, por exemplo /api/v2/....

A especificação OpenAPI 3.1 está em /docs/api/openapi.yaml.