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.
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.
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.
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.
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
/api/v1/account
library:read
O workspace por trás da chave: plano, entitlement e cota de publicações.
/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
/api/v1/tools
tools:run
O catálogo de ferramentas que a API expõe, com seus flags de medição.
/api/v1/uploads
library:write
Gera um PUT pré-assinado para um arquivo novo (30 minutos).
/api/v1/publications
library:write
Registra um objeto enviado como publicação.
/api/v1/publications
library:read
Lista as publicações do workspace (paginação por cursor).
/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
/api/v1/publications/{id}/files
library:read
O histórico completo de versões: o original imutável mais cada cópia aprimorada.
/api/v1/publications/{id}/files/current
library:read
A versão de trabalho — sobre a qual a próxima ferramenta age.
/api/v1/files/{id}/download
library:read
302 para um link de download de curta duração de qualquer versão.
/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.
/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
/api/v1/publications/{id}/runs
tools:run
Inicia uma execução (202). Aceita um objeto options e um header Idempotency-Key.
/api/v1/publications/{id}/runs
library:read
Lista os runs de uma publicação, filtrável por ferramenta.
/api/v1/runs/{id}
library:read
Estado, tempos e detalhe de erro do run.
/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 MCPConectar 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.