Ir para o conteúdo
API do Origami

A linha de produção, programável

Tudo o que o workspace faz — enviar, avaliar, aprimorar, baixar — controlado a partir dos seus próprios sistemas com uma API JSON simples.

O ciclo

A API reflete o workspace: quatro etapas, repetidas por livro.

01

Enviar

Você declara o arquivo, faz PUT dos bytes para uma URL pré-assinada e registra a publicação. Os arquivos nunca passam pela API.

02

Rodar

Você inicia qualquer ferramenta contra a versão de trabalho da publicação. A resposta é um run que você consulta — as ferramentas síncronas terminam na primeira consulta.

03

Ler

Você obtém o relatório JSON do run: constatações, pontuações, metadados ou a descrição para a página da publicação.

04

Baixar

As reparações e edições adicionam novas versões do arquivo. Você baixa a versão de trabalho com um link de curta duração.

URL base e autenticação

Cada request carrega uma chave de API de workspace como token Bearer. A chave está atrelada a um workspace: tudo o que você cria e lê com ela vive ali, exatamente como se estivesse trabalhando no app. Não existe nenhum parâmetro de workspace nesta API — a chave é o que nomeia o tenant, então uma chave só consegue alcançar a própria biblioteca.

URL base

https://origami.publica.la/api/v1

Todos os caminhos desta página são relativos a isso. Requests e respostas são JSON; envie Accept: application/json e, num POST, Content-Type: application/json.

Uma primeira chamada

curl https://origami.publica.la/api/v1/publications \
  -H "Authorization: Bearer ${ORIGAMI_API_KEY}" \
  -H "Accept: application/json"

Obter uma chave

Quem tem papel de proprietário ou admin gera as chaves em Configurações → Chaves de API. O valor é exibido uma única vez e nunca mais — só o hash é guardado — então leve-o direto para o seu gerenciador de segredos. A mesma tela revoga uma chave, e a revogação vale já no request seguinte.

Uma chave pertence tanto a quem a gerou quanto ao workspace. Se essa pessoa sair do workspace, as chaves dela param de funcionar com membership_revoked — então gere as chaves de integração a partir de uma conta que vá durar mais que a integração.

Permissões

Uma chave carrega apenas as permissões com que foi criada, e cada rota verifica exatamente uma. Um request que apresenta uma chave sem a permissão de que a rota precisa é recusado com 403.

library:read

Ler o workspace, suas publicações, versões de arquivo, execuções, relatórios e espelhos do reader.

library:write

Gerar locais de upload, registrar publicações e reenviar uma publicação para a loja reader.

tools:run

Listar o catálogo de ferramentas e iniciar execuções.

Início rápido

Seis requests levam um livro do seu disco a um relatório de validação, ida e volta. Substitua o token e o nome do arquivo; o resto é copiar e colar.

1 · Peça um local de upload

curl -X POST https://origami.publica.la/api/v1/uploads \
  -H "Authorization: Bearer ${ORIGAMI_API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{"original_filename": "book.epub", "size_bytes": 4180294}'

Responde 201 com um publication_id, a key de storage, a upload_url para onde fazer PUT, os headers com que essa URL foi assinada e o seu expires_at — 30 minutos adiante.

2 · PUT dos bytes para a URL pré-assinada

curl -X PUT "UPLOAD_URL_FROM_STEP_1" \
  -H "Content-Type: application/epub+zip" \
  --data-binary @book.epub

Envie cada header que o passo anterior devolveu, literalmente. O upload vai direto para o storage: nenhum byte passa pela API, então um livro de 2 GB sobe na velocidade do bucket e não na de um request PHP.

3 · Registre a publicação

curl -X POST https://origami.publica.la/api/v1/publications \
  -H "Authorization: Bearer ${ORIGAMI_API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{"publication_id": "ID_FROM_STEP_1", "key": "KEY_FROM_STEP_1", "original_filename": "book.epub", "size_bytes": 4180294}'

Devolva o mesmo publication_id, key, original_filename e size_bytes. O tamanho é comparado com o que realmente chegou, então um upload truncado é recusado aqui e não descoberto na primeira execução.

4 · Rode uma ferramenta

curl -X POST https://origami.publica.la/api/v1/publications/PUBLICATION_ID/runs \
  -H "Authorization: Bearer ${ORIGAMI_API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{"tool": "epub-check"}'

Responde 202 com um run. Um run sempre age sobre a versão de trabalho da publicação — o arquivo mais novo que uma ferramenta produziu, ou o original se não houver nenhum.

5 · Consulte o run e leia o relatório

curl https://origami.publica.la/api/v1/runs/RUN_ID \
  -H "Authorization: Bearer ${ORIGAMI_API_KEY}"

curl https://origami.publica.la/api/v1/runs/RUN_ID/report \
  -H "Authorization: Bearer ${ORIGAMI_API_KEY}"

Consulte até que status seja terminal. O endpoint de relatório responde 409 run_not_finished enquanto o run continua, então consultar o run primeiro é o ciclo mais econômico.

6 · Baixe a versão de trabalho

curl https://origami.publica.la/api/v1/publications/PUBLICATION_ID/files/current \
  -H "Authorization: Bearer ${ORIGAMI_API_KEY}"

curl -L -o book-improved.epub \
  https://origami.publica.la/api/v1/files/FILE_ID/download \
  -H "Authorization: Bearer ${ORIGAMI_API_KEY}"

O endpoint de download responde um 302 para um GET pré-assinado válido por 10 minutos. Siga os redirects (curl -L) e não guarde o destino em cache.

Endpoints

Todos os endpoints vivem sob /api/v1, falam JSON e respondem erros como {error, reason, detail} com um reason estável para máquinas. A coluna de permissão é a que cada rota verifica.

Workspace

GET /api/v1/account library:read

O workspace por trás da chave: plano, entitlement e cota de publicações.

GET /api/v1/account/usage library:read

O uso de hoje das ferramentas medidas contra o limite diário, mais o que resta da cota de publicações.

Request e resposta

Request

curl "https://origami.publica.la/api/v1/account" \
  -H "Authorization: Bearer ${ORIGAMI_API_KEY}"

Resposta

{
  "data": {
    "id": "01JQ8ZW4M3S9F0AC2KQ7X6HV1B",
    "name": "Ediciones Ejemplo",
    "type": "standalone",
    "plan": { "slug": "pro", "name": "Pro" },
    "subscribed": true,
    "on_trial": false,
    "entitled": true,
    "unlimited": false,
    "publications": {
      "used": 2,
      "limit": 5,
      "remaining": 3,
      "resets_at": "2026-10-08T00:00:00+00:00",
      "granted_remaining": 0,
      "promotional_remaining": 0
    }
  }
}

Publicações e uploads

GET /api/v1/tools tools:run

O catálogo de ferramentas que a API expõe, com seus flags de medição.

POST /api/v1/uploads library:write

Gera um PUT pré-assinado para um arquivo novo (30 minutos).

POST /api/v1/publications library:write

Registra um objeto enviado como publicação.

GET /api/v1/publications library:read

Lista as publicações do workspace (paginação por cursor).

GET /api/v1/publications/{id} library:read

Uma publicação: tipo, estado, título, arquivo de trabalho.

Request e resposta

Request

curl -X POST "https://origami.publica.la/api/v1/uploads" \
  -H "Authorization: Bearer ${ORIGAMI_API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{"original_filename": "book.epub", "size_bytes": 4180294}'

Resposta

{
  "data": {
    "publication_id": "01JQ90R2VTA6E4M8YN5D3PKC7F",
    "key": "accounts/01JQ8ZW4.../uploads/01JQ90R2....epub",
    "upload_url": "https://storage.example/...&X-Amz-Signature=...",
    "headers": { "Content-Type": "application/epub+zip" },
    "expires_at": "2026-09-04T13:21:00+00:00"
  }
}

Versões de arquivo

GET /api/v1/publications/{id}/files library:read

O histórico completo de versões: o original imutável mais cada cópia aprimorada.

GET /api/v1/publications/{id}/files/current library:read

A versão de trabalho — sobre a qual a próxima ferramenta age.

GET /api/v1/files/{id}/download library:read

302 para um link de download de curta duração de qualquer versão.

GET /api/v1/publications/{id}/reader library:read

Os espelhos da publicação na loja reader da publica.la, e se a integração está configurada.

POST /api/v1/publications/{id}/reader/sync library:write

Reenvia um espelho para o reader da publica.la (202) — resgata uma primeira publicação que falhou ou repete uma conversão travada.

Request e resposta

Request

curl "https://origami.publica.la/api/v1/publications/PUBLICATION_ID/files/current" \
  -H "Authorization: Bearer ${ORIGAMI_API_KEY}"

Resposta

{
  "data": {
    "id": "01JQ93B8KDW1H7RZ4T0NQXME62",
    "publication_id": "01JQ90R2VTA6E4M8YN5D3PKC7F",
    "role": "derived",
    "derived_kind": "epub-repair",
    "original_filename": "book.epub",
    "mime_type": "application/epub+zip",
    "size_bytes": 4194512,
    "reverted": false,
    "current": true,
    "created_at": "2026-09-04T12:58:41+00:00"
  }
}

Execuções de ferramentas

POST /api/v1/publications/{id}/runs tools:run

Inicia uma execução (202). Aceita um objeto options e um header Idempotency-Key.

GET /api/v1/publications/{id}/runs library:read

Lista os runs de uma publicação, filtrável por ferramenta.

GET /api/v1/runs/{id} library:read

Estado, tempos e detalhe de erro do run.

GET /api/v1/runs/{id}/report library:read

O relatório JSON do run concluído.

Request e resposta

Request

curl -X POST "https://origami.publica.la/api/v1/publications/PUBLICATION_ID/runs" \
  -H "Authorization: Bearer ${ORIGAMI_API_KEY}" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 5f3a-nightly-sweep-0042" \
  -d '{"tool": "epub-accessibility"}'

Resposta

{
  "data": {
    "id": "01JQ95T1YB0PJ6VF8C3WKR2HQD",
    "publication_id": "01JQ90R2VTA6E4M8YN5D3PKC7F",
    "tool": "epub-accessibility",
    "status": "queued",
    "error_reason": null,
    "error_detail": null,
    "started_at": null,
    "finished_at": null,
    "duration_ms": null,
    "created_at": "2026-09-04T13:02:10+00:00"
  }
}

Os quatro recursos

Quatro formas cobrem toda a API, e cada endpoint que devolve uma devolve-a de forma idêntica.

Workspace

Em qual workspace a chave caiu, se ela pode fazer trabalho pago (entitled — mais amplo que subscribed, porque uma loja da publica.la carrega um plano sem assinatura do Stripe por trás) e a cota de publicações. remaining soma a cota do ciclo do plano, os lugares concedidos pela equipe e o que uma promoção ainda cobrir — é o único número que responde «posso adicionar outro livro?». Quando o Stripe não pode ser alcançado, plan e publications voltam como null e não como zero: desconhecido, não esgotado.

Publicação

Um livro, um audiolivro ou um documento de origem do workspace. current_file_id aponta para a versão de trabalho, que é a que a próxima execução lê, e current_file_bytes é o que essa versão pesa hoje — storage_bytes continua sendo o tamanho do original como foi enviado, então um livro otimizado informa dois números diferentes.

Versão de arquivo

Uma versão de uma publicação. O original é imutável e nunca é substituído; cada ferramenta que escreve adiciona uma versão nova, então o histórico fica completo. current marca a de trabalho e reverted marca uma versão revertida no app.

Execução

Uma execução de uma ferramenta sobre uma publicação. status chega a succeeded, failed ou rejected e não muda mais; error_reason e error_detail dizem por quê nos outros dois casos.

Catálogo de ferramentas

Os slugs que POST /publications/{id}/runs aceita, lidos ao vivo deste deployment — GET /api/v1/tools devolve a mesma lista em JSON. Dois flags importam quando você encadeia chamadas.

Slug Ferramenta Categoria Flags
epub-metadata EPUB Metadata Extractor metadata medida
epub-description EPUB Description Writer description medida
epub-metadata-write EPUB Metadata Editor metadata escreve a versão de trabalho
epub-toc EPUB Table of Contents toc medida
epub-toc-generate EPUB Table of Contents Generator toc medida
epub-toc-write EPUB Table of Contents Editor toc escreve a versão de trabalho
epub-check EPUB Checker validation
epub-accessibility EPUB Accessibility Checker accessibility
epub-repair EPUB Repair repair medida escreve a versão de trabalho
epub-qualebook Qualebook Quality Checklist quality
epub-qualebook-review Qualebook AI Review quality medida
cover-replace Cover Change cover escreve a versão de trabalho
onix-export ONIX File Creator metadata
social-copy Social Campaign Writer marketing medida
social-image Social Image Generator marketing medida
social-carousel Social Carousel Generator marketing medida
social-video Social Video Generator marketing medida
pdf-check PDF Diagnosis validation
pdf-accessibility PDF Accessibility Checker accessibility
pdf-accessibility-fix PDF Accessibility Fix accessibility escreve a versão de trabalho
pdf-autotag PDF Auto-Tag accessibility medida escreve a versão de trabalho
pdf-alt-text PDF Alt Text accessibility medida escreve a versão de trabalho
pdf-repair PDF Repair repair medida escreve a versão de trabalho
asset-optimize Asset Optimizer repair medida escreve a versão de trabalho
pdf-epub-analyze PDF to EPUB Analyzer conversion
pdf-epub-convert PDF to EPUB Converter conversion medida
document-epub-convert Document to EPUB Converter conversion medida

Um slug que este deployment não expõe responde 404 unknown_tool; um que existe mas ainda não foi liberado responde 409 tool_unavailable. As opções são próprias de cada ferramenta e vão num objeto options — uma opção que a ferramenta não reconhece é ignorada em vez de recusada, então confira o relatório para confirmar o que realmente rodou. A exceção é uma opção que mudaria o que a execução tem permissão de fazer: uma opção que faria a execução depender de uma pessoa, enviada a uma execução que se aplica sozinha, é recusada com 422 invalid_options em vez de ser ampliada em silêncio.

Convenções

Assíncrono por padrão

Os runs respondem 202 com um recurso que você consulta. Um run é terminal em succeeded, failed ou rejected. Ainda não há webhooks, então consulte — um ou dois segundos entre tentativas é suficiente; nada aqui termina mais rápido do que a fila levanta.

Idempotência

Envie um header Idempotency-Key no POST /runs; uma nova tentativa devolve o run original com 200 em vez de gastar duas vezes, e uma tentativa que chega enquanto a primeira ainda está sendo registrada responde 409 idempotency_in_flight.

Paginação

As listas respondem {data, next_cursor, has_more} com 50 linhas por página, da mais nova para a mais antiga. Passe next_cursor como ?cursor= até has_more ser false. O cursor é um id e não um offset, então um livro adicionado enquanto você pagina não desloca a janela.

Limites de taxa

Os requests são limitados a 60 por minuto por chave — por chave, então duas integrações num workspace não dividem a mesma cota. Acima do teto vem um 429; espere e tente de novo.

Dois tetos de gasto

Os uploads consomem a cota de publicações do plano (422 publication_quota_exceeded) e as ferramentas medidas consomem a cota diária de uso justo do workspace (429 daily_limit_reached com Retry-After). GET /account e GET /account/usage informam as duas antes de gastar qualquer uma.

Os arquivos vão direto

Os uploads são PUTs pré-assinados e os downloads GETs pré-assinados contra o storage — a API nunca faz proxy dos bytes, então as transferências são rápidas em qualquer tamanho. Os links de upload vivem 30 minutos; os de download, 10.

Descrições

A ferramenta de descrições devolve o texto para a página da publicação: um único estilo (back_cover) com uma versão longa para o corpo e uma curta para cartões e metadados. Os estilos de catálogo e de livraria que ela também escreve ficam dentro do app.

Datas e ids

Cada timestamp é ISO 8601 com offset. Cada id é um ULID — ordenável, então ordenar por id é ordenar por data de criação.

Erros

Cada falha responde o mesmo envelope. reason é a string estável para máquinas na qual ramificar — o status HTTP diz a classe do problema, o reason diz qual é.

O envelope

{
  "error": "Publication not found.",
  "reason": "publication_not_found",
  "detail": null
}

Um corpo de request malformado devolve a resposta de validação do próprio Laravel ({message, errors}) e não este envelope — o envelope é para falhas que a API decidiu, a forma de validação para um corpo que ela não conseguiu ler.

Status Reason O que significa
401 invalid_token Sem chave, com uma chave desconhecida, ou com uma que foi revogada.
403 token_without_workspace A chave não está atrelada a um workspace — uma chave de operador numa rota de cliente.
403 membership_revoked Quem gerou a chave já não pertence a este workspace. Gere uma chave nova a partir de um membro atual.
404 publication_not_found Não há publicação com esse id neste workspace. Os ids nunca são compartilhados entre workspaces.
404 file_not_found Não existe essa versão de arquivo, ou a publicação ainda não tem arquivo.
404 run_not_found Não há execução com esse id neste workspace.
404 unknown_tool Esse slug não é uma ferramenta que esta API exponha. GET /tools é a lista autoritativa.
409 tool_unavailable A ferramenta existe mas ainda não foi liberada.
409 working_file_busy Outra execução que escreve a versão de trabalho detém esta publicação. Libera quando essa execução termina — nenhum Retry-After pode dizer quando, então consulte o run.
409 run_not_finished O relatório foi pedido antes de a execução alcançar um estado terminal.
409 run_not_succeeded A execução é terminal mas não teve sucesso, então não há relatório. O recurso do run diz por quê.
409 approval_required O resultado desta execução precisa de uma pessoa comparando exemplos de antes e depois, o que só o app do Origami mostra. Nem esperar nem assinar resolve.
409 idempotency_in_flight Um request com a mesma Idempotency-Key ainda está sendo registrado. Tente de novo em instantes.
409 reader_not_configured Este deployment não tem integração com o reader da publica.la.
409 reader_sync_in_progress Já há um envio da mesma variante para a loja reader em curso.
409 downloads_unavailable O backend de storage não consegue gerar links pré-assinados. Só aparece no storage local de desenvolvimento.
422 publication_quota_exceeded O workspace gastou a cota de publicações do ciclo. O detalhe diz quando ela renova.
422 unsupported_format Não é um formato de livro, documento de origem ou audiolivro que o Origami aceite.
422 invalid_options O objeto options não é válido para essa ferramenta.
402 plan_required O workspace não tem plano ativo, então nenhuma execução pode começar. Os endpoints de leitura continuam funcionando — por isso não é um 403.
429 daily_limit_reached O workspace alcançou o limite diário de uso justo em execuções medidas. Carrega Retry-After.

Também por MCP

O Origami fala MCP (Model Context Protocol) em https://origami.publica.la/mcp por Streamable HTTP, então um agente pode explorar seu workspace e rodar ferramentas igual a esta API.

Conecte-se com uma chave de API de workspace como token Bearer, ou por OAuth nos clientes que suportarem. Cada ferramenta reflete um endpoint acima — mesmo serviço, mesmo workspace, mesmas cotas — então um agente e um cliente HTTP veem um só produto.

O que você pode fazer por MCP

Conectar do Claude Code

claude mcp add --transport http origami https://origami.publica.la/mcp \
  --header "Authorization: Bearer ${ORIGAMI_API_KEY}"

Construindo uma integração?

Conte o que você está automatizando — ingestão em massa, um hook do seu DAM, um pipeline de preflight — e ajudamos a conectar.