Relatórios para bibliotecas
API somente leitura que expõe, de forma programática, o que o painel de Relatórios da rede de bibliotecas mostra: KPIs agregados, engajamento diário por leitor, cadastro de leitores, acervo, estoque, empréstimos, reservas, acessos e sugestões de compra.
São cinco rotas, organizadas pelo grão do dado:
| Rota | Grão | Entrega |
|---|---|---|
GET /libraries/v1/summary | agregado do período | todos os KPIs numa chamada |
GET /libraries/v1/engagements | dia × leitor | métricas diárias por leitor |
GET /libraries/v1/users | 1 linha por leitor | cadastro, inclusive desativados e excluídos |
GET /libraries/v1/datasets/{name} | linha a linha | livros, estoque, empréstimos, reservas, logins, canais, sugestões |
GET /libraries/v1/dimensions | vocabulário | valores válidos de filtro |
Acesso
| Item | Valor |
|---|---|
| Host | https://livros.arvore.com.br |
| Base path | /api-arvore/libraries/v1 (o prefixo antigo /api-arvore/biblion/v1 continua respondendo por compatibilidade, mas não use em integração nova) |
| Autenticação | Header X-Api-Key: <chave> (alternativa: Authorization: Bearer <chave>). Chave emitida pela Árvore, exclusiva desta API. Sem chave válida: 401 |
| Tenant | Fixo no servidor (escopo BibliON). A API não aceita identificador de tenant do cliente |
| Formato | JSON UTF-8, somente GET |
| Rate limit | 60 requisições por minuto, compartilhadas por toda a integração; excedente recebe 429 com header Retry-After. Toda resposta traz o saldo em x-ratelimit-remaining-public-default |
Exemplo:
curl -s \
-H 'X-Api-Key: <chave>' \
'https://livros.arvore.com.br/api-arvore/libraries/v1/summary?startDate=2026-08-01&endDate=2026-08-31'
Convenções e tipos
| Tipo | Formato | Exemplo |
|---|---|---|
int | inteiro não-negativo | 42457 |
string | texto UTF-8 | "Olhos d'água" |
bool | true / false | true |
date | YYYY-MM-DD, fuso de Brasília (UTC−3) | "2026-08-26" |
datetime | YYYY-MM-DD HH:mm:ss, fuso de Brasília | "2026-08-26 14:03:11" |
frac | fração decimal onde 1 = 100% (18,5% = 0.185). Razões de consumo podem passar de 1; o campo diz quando | 0.185 |
percent | percentual de 0 a 100, com casas decimais | 99.32 |
money | string decimal com ponto, em reais | "62.90" |
enum | um valor do conjunto listado no campo | "active" |
- Tempo lido ou ouvido é sempre em segundos inteiros.
- Campos sem valor vêm como
null, nunca omitidos. - Parâmetros de data usam
YYYY-MM-DD; outro formato responde400. startDateeendDatesão inclusivos. Quando opcionais e omitidos, valem os últimos 30 dias (de 30 dias atrás até hoje, em Brasília). SestartDatevier depois deendDate, o servidor inverte os dois.- Parâmetros booleanos (
newUsers) recebem a stringtrueoufalse. - Ids de dimensão (
libraryId,ageGroupId,publisherId,categoryId,subjectId) são inteiros. O/dimensionsdevolve esses ids como string; converta antes de enviar. - Histórico começa em 2026-07-21, data de entrada da BibliON na plataforma. Empréstimos, devoluções, renovações e reservas anteriores não existem na base.
Paginação
page começa em 1 (default 1). pageSize tem default 100 e o máximo depende da rota:
| Rota | pageSize máximo |
|---|---|
/engagements | 1000 |
/users | 1000 |
/summary (pagina só o breakdown) | 100 |
/datasets/loans, reservations, logins, suggestion-requests | 1000 |
/datasets/books, stock, suggestions | 100 |
pageSize acima do máximo responde 400. page vai até 100000. O total de linhas vem em meta.page.totalRows.
Janela máxima
/engagements, datasets/logins e datasets/channels aceitam no máximo 31 dias por chamada (400 acima disso). Ingestões maiores fatiam por mês.
Datas são YYYY-MM-DD e precisam existir no calendário: 2026-02-30 ou 2026-01-00 respondem 400.
Cliente HTTP
O host fica atrás de um WAF que barra requisições com o User-Agent padrão do urllib do Python (Python-urllib/3.x), respondendo 403 antes de a chamada chegar à API. Defina um User-Agent próprio na sua integração, por exemplo BibliON-Ingest/1.0. Clientes comuns (requests, axios, HttpClient do Java, Go) passam sem ajuste.
Atualização dos dados
Os dados vêm do lakehouse da Árvore, sincronizados ao longo do dia. Não são tempo real. As respostas são calculadas por hora cheia: meta.updatedAt traz essa hora (ex.: 2026-09-04 18:00:00), e a mesma consulta repetida devolve o mesmo resultado até a hora virar. Não há ganho em repetir a mesma chamada dentro da hora.
Envelope de resposta
Toda rota responde neste formato. data varia por rota; meta é sempre igual.
{
"meta": {
"updatedAt": "2026-08-27 09:59:12",
"period": { "startDate": "2026-07-28", "endDate": "2026-08-27" },
"page": { "page": 1, "pageSize": 100, "totalRows": 9317 }
},
"data": { }
}
| Campo | Tipo | Descrição |
|---|---|---|
meta.updatedAt | datetime | null | Último sync do lakehouse |
meta.period.startDate | date | Início efetivo do período consultado (após defaults) |
meta.period.endDate | date | Fim efetivo do período |
meta.page.* | int | page, pageSize, totalRows |
data | object | Conteúdo da rota; em listagens, data.rows é o array de linhas |
meta.period aparece nas rotas que aceitam período (/summary, /engagements, /datasets/*). meta.page aparece nas respostas paginadas; no /summary só quando há groupBy. /dimensions traz apenas meta.updatedAt.
GET /libraries/v1/summary
Todos os agregados do painel numa chamada. Com groupBy, devolve também a quebra por dimensão.
Parâmetros
| Param | Tipo | Obrigatório | Descrição |
|---|---|---|---|
startDate / endDate | date | não | Período. Default: últimos 30 dias |
groupBy | enum | não | library | state | city | ageGroup. Popula data.breakdown |
libraryId | int | não | Filtra por biblioteca (id do /dimensions) |
state | string | não | UF do leitor, ex. SP |
city | string | não | Cidade do leitor |
ageGroupId | int | não | Faixa etária (id do /dimensions) |
gender | string | não | Gênero canônico (valores no /dimensions) |
newUsers | bool | não | Só leitores cadastrados dentro do período |
page / pageSize | int | não | Paginam apenas o breakdown (máximo 100) |
Escopo dos filtros: libraryId, state, city, ageGroupId, gender e newUsers recortam apenas os blocos general e breakdown. Os demais blocos (consumption, channels, formats, reservationsByStatus, stock, deletedUsers, catalogProfile, monthly) são sempre da base inteira no período.
data.general
| Campo | Tipo | Descrição |
|---|---|---|
registeredUsers | int | Total de cadastros na base (acumulado, não recortado pelo período) |
logins | int | Dias com atividade, somados por leitor: um leitor ativo em 3 dias do período conta 3 |
usersWithLogin | int | Leitores distintos com atividade no período |
loans | int | Empréstimos no período |
returns | int | Devoluções no período (inclui expiração automática) |
activeLoans | int | Empréstimos menos devoluções no período |
readings10 | int | Leituras que atingiram 10% do livro |
readings50 | int | Leituras que atingiram 50% (livro concluído) |
previews | int | Prévias: visualizações sem empréstimo |
distinctBooks | int | Livros distintos lidos |
readingSeconds | int | Tempo total lido, em segundos |
renewals | int | Renovações de empréstimo |
reservations | int | Reservas feitas no período |
activeReservations | int | Reservas ativas agora (foto do momento do sync) |
convertedReservations | int | Reservas feitas no período que viraram empréstimo |
data.consumption
| Campo | Tipo | Descrição |
|---|---|---|
onlineSessions | int | Sessões de leitura on-line (streaming) |
offlineSessions | int | Sessões off-line (download) |
onlineSeconds | int | Tempo lido on-line, em segundos |
offlineSeconds | int | Tempo lido off-line, em segundos |
data.channels
Sessões por canal de acesso, medidas pela ferramenta de analytics (PostHog).
| Campo | Tipo | Descrição |
|---|---|---|
available | bool | Se o analytics respondeu; false zera os demais campos |
appEstimated | bool | O número do app é estimado (o webview não informa a oferta) |
total | int | Sessões totais no período |
web | int | Sessões via navegador |
app | int | Sessões via aplicativo (estimado) |
webMobile / webDesktop / webTablet | int | Web por tipo de aparelho |
data.formats
| Campo | Tipo | Descrição |
|---|---|---|
catalog.ebookOnly / audiobookOnly / both | int | Títulos do catálogo por formato |
loans.ebookOnly / audiobookOnly / both | int | Empréstimos do período pela mesma quebra |
listening.listeners | int | Ouvintes distintos de audiobook no período |
listening.seconds | int | Tempo ouvido, em segundos |
data.reservationsByStatus
| Campo | Tipo | Descrição |
|---|---|---|
active | int | Aguardando na fila ou disponíveis para retirada |
converted | int | Viraram empréstimo no período |
cancelled | int | Canceladas pelo leitor no período |
lost | int | Expiraram sem retirada no período |
data.stock
| Campo | Tipo | Descrição |
|---|---|---|
activeLoans | int | Empréstimos ativos agora |
readings | int | Leituras confirmadas (10% do livro) de leitores com empréstimo desde 2026-07-21, somando compras e legado |
possibleReadings | int | Leituras possíveis: cópias × modelo em cada compra e em cada linha de legado. No legado Odilo cada cópia vale 1 leitura; nos demais vale max_uses do título, ou 26 quando o título não define |
percentage | frac | Consumidas ÷ possíveis no acervo inteiro. Sempre entre 0 e 1 |
activeReservations | int | Reservas ativas agora |
histogram[] | array | Faixas de consumo: { band: string, count: int }, ex. {"band":"1-10","count":216} |
data.deletedUsers
Cadastros desativados ou excluídos desde 2026-07-21.
| Campo | Tipo | Descrição |
|---|---|---|
total | int | Total acumulado (sem recorte de período) |
last30Days | int | Desativações nos últimos 30 dias |
withLoans | int | Desativados com empréstimos preservados |
daily[] | array | Últimos 30 dias: { date: date, total: int } |
monthly[] | array | Por mês: { month: "YYYY-MM", total: int } |
data.catalogProfile
| Campo | Tipo | Descrição |
|---|---|---|
categories[] | array | Por categoria: { name, catalogTitles: int, loans: int } |
subjects[] | array | Por assunto, mesmo formato |
origins[] | array | Por procedência do catálogo, mesmo formato |
materials.ebook / audiobook | object | { catalogTitles: int, loans: int } |
materials.video | object | null | Mesmo formato; null sem vídeo no acervo |
data.monthly[]
| Campo | Tipo | Descrição |
|---|---|---|
month | string | YYYY-MM |
loans / readings10 / readings50 / renewals | int | Métricas no mês |
readingSeconds | int | Tempo lido no mês, em segundos |
data.breakdown[] (com groupBy)
| Campo | Tipo | Descrição |
|---|---|---|
key | string | Id do grupo. Para library e ageGroup é o id do /dimensions; para state e city é o próprio nome |
label | string | Nome exibível do grupo |
metrics | object | Mesmos campos de data.general, recortados para o grupo |
Grupos sem valor no cadastro do leitor aparecem com label Não informado.
GET /libraries/v1/engagements
Engajamento diário no grão dia × leitor, esparso: uma linha por leitor por dia, somente quando houve atividade. Leitor sem métrica no dia não gera linha. Ordenação fixa date ASC, userId ASC, estável para ingestão incremental.
Somando as linhas de um dia, logins, loans, returns, readings10, readings50, previews, readingSeconds, renewals e reservations batem com o data.general do /summary para o mesmo dia. distinctBooks não soma: é distinto por leitor, e no /summary é distinto na base inteira.
Parâmetros
| Param | Tipo | Obrigatório | Descrição |
|---|---|---|---|
startDate | date | sim | Início da janela |
endDate | date | sim | Fim da janela. Máximo de 31 dias por chamada |
userId | int | não | Restringe a um leitor |
page / pageSize | int | não | Paginação (máximo 1000) |
data.rows[]
| Campo | Tipo | Descrição |
|---|---|---|
date | date | Dia de referência |
userId | int | Leitor. Detalhe no /users |
logins | int | 1 se o leitor teve atividade no dia, 0 caso contrário |
loans | int | Empréstimos feitos no dia |
returns | int | Devoluções no dia |
readings10 | int | Leituras que cruzaram 10% no dia |
readings50 | int | Leituras que cruzaram 50% no dia |
previews | int | Prévias no dia |
distinctBooks | int | Livros distintos lidos no dia |
readingSeconds | int | Tempo lido no dia, em segundos |
renewals | int | Renovações no dia |
reservations | int | Reservas feitas no dia |
reservationsConverted | int | Das reservas feitas no dia, quantas vieram a virar empréstimo (a data é a da reserva, não a da conversão) |
GET /libraries/v1/users
Cadastro dos leitores. É o único lugar da API com dado nominal; as demais rotas referenciam o leitor por userId. Inclui ativos, desativados e excluídos. Ordenação fixa userId ASC.
Parâmetros
| Param | Tipo | Obrigatório | Descrição |
|---|---|---|---|
userId | int | não | Um leitor específico |
status | enum | não | active | deactivated | deleted. Default: todos |
libraryId | int | não | Filtra por biblioteca |
registeredFrom / registeredTo | date | não | Recorte pela data de cadastro. É assim que se conta “leitores cadastrados” por período |
updatedSince | date | não | Só cadastros alterados desde a data, inclusive desativação e exclusão (conferido: 100% das desativações tocam a data de alteração). Base do sync incremental |
page / pageSize | int | não | Paginação (máximo 1000) |
data.rows[]
| Campo | Tipo | Descrição |
|---|---|---|
userId | int | Identificador do leitor, chave usada nas demais rotas |
name | string | Nome |
email | string | |
library | string | null | Biblioteca do cadastro |
ageGroup | string | null | Faixa etária |
city | string | null | Cidade informada no cadastro |
state | string | null | UF |
gender | string | Feminino | Masculino | Não-binário | Outro | Não informado |
registeredAt | date | Data do cadastro |
status | enum | active em uso · deactivated bloqueado pela biblioteca · deleted excluído pelo leitor |
deletedAt | date | null | Data da desativação ou exclusão; null para ativos |
updatedAt | datetime | Última alteração do cadastro, ISO 8601 em UTC (2026-08-14T13:02:11Z). É o campo para decidir o que mudou dentro de um lote do updatedSince |
confirmedAt | datetime | null | Quando o leitor confirmou o e-mail; null enquanto pendente |
lastSignInAt | datetime | null | Último acesso à plataforma; null para quem nunca entrou |
totalLoans | int | Empréstimos históricos (preservados mesmo após exclusão) |
A tela de cadastros excluídos do painel (e o bloco deletedUsers do /summary) soma deactivated e deleted com deletedAt a partir de 2026-07-21. status=deleted sozinho devolve só quem se excluiu, que é uma fração pequena desse total.
Sincronizar leitores com um CRM
Receita para manter uma base externa (HubSpot, RD Station, planilha) espelhando o cadastro, sem varrer tudo a cada rodada:
- Carga inicial: percorra
GET /libraries/v1/users?pageSize=1000&page=Nem sequência, uma página por vez, atémeta.page.totalRows. A rota passa pela fila de consultas pesadas, então páginas em paralelo podem responder503; em sequência não. Ordem de referência: uma página de 1000 leva cerca de 2 segundos, e a base inteira (~636 mil leitores) sai em torno de 20 minutos. A ordenação é fixa poruserIde cadastros excluídos continuam na lista (comstatusdeleted), então paginar porpagenão perde nem repete linha enquanto a base cresce. - Rodada diária: chame
GET /libraries/v1/users?updatedSince=<ontem>e aplique linha a linha:statusdiz se o contato segue ativo, foi bloqueado pela biblioteca (deactivated) ou se excluiu (deleted);updatedAtdesempata quando a mesma pessoa aparece em duas rodadas.updatedSincetem grão de dia, então repita o dia anterior inteiro e deixe ouserIdser a chave de deduplicação. - Chave do contato: use
userId, nunca o e-mail. O e-mail pode mudar e, em cadastro excluído, é apagado na origem. - Frequência: os dados atualizam a cada hora cheia (
meta.updatedAt); chamar mais de uma vez por hora devolve o mesmo resultado. Uma rodada por dia costuma bastar.
Não há webhook, evento push nem ambiente de homologação. A API é somente leitura e não altera nada na plataforma, então o próprio ambiente de produção é onde se integra: use uma janela curta (pageSize pequeno, ou updatedSince de ontem) para conferir o formato antes de rodar a carga inteira. A única forma de saber que um cadastro mudou é a rodada com updatedSince. Também não há telefone, endereço ou documento no payload; a API entrega o mínimo necessário para identificar e segmentar o contato (library, ageGroup, city, state, gender). Cadastros de menores de idade estão na base e aparecem com ageGroup correspondente: quem sincroniza para um CRM responde pelo tratamento desse dado no destino.
GET /libraries/v1/datasets/{name}
Dados linha a linha, paginados (máximo por página na tabela de paginação acima), com o envelope padrão. Linhas referenciam o leitor por userId e o título por bookId. Dataset desconhecido responde 404.
| Dataset | Grão | Resumo |
|---|---|---|
books | 1 linha por título | Uso e acervo por livro no período |
stock | 1 linha por título (+ compras) | Consumo do estoque, preços e expiração |
loans | 1 linha por empréstimo | Cada empréstimo, com leitura acumulada do leitor no título |
reservations | 1 linha por reserva | Ciclo completo, com status e datas |
logins | 1 linha por leitor × dia | Dias com atividade de cada leitor, com primeiro e último evento |
channels | 1 linha por dia × aparelho | Sessões por canal de acesso |
suggestions | 1 linha por título sugerido | Sugestões de compra agregadas por título |
suggestion-requests | 1 linha por pedido | Cada solicitação, com o leitor |
Parâmetro do vocabulário desta rota que não se aplica ao dataset é ignorado (ex.: status em books). Nome de parâmetro fora do vocabulário responde 400 com property <nome> should not exist, e isso inclui o antigo method de logins, que não existe mais. orderBy fora da lista do dataset, status fora do conjunto do dataset ou collection fora do vocabulário do dataset respondem 400.
datasets/books
Parâmetros: startDate/endDate (janela das métricas de uso), search (título ou ISBN), author, publisherId, categoryId, subjectId, collection (all | platform | additional | odilo | manual), format (ebook | audiobook), bookId, publicationYear, orderBy (title | loans | returns | readings10 | readings50 | readingSeconds | renewals | reservations | activeReservations | convertedReservations, default loans), orderDir (asc | desc, default desc), page/pageSize. Desempate por título e bookId, então a ordem é total e a paginação não repete linha.
| Campo | Tipo | Descrição |
|---|---|---|
bookId | int | Identificador do título |
title | string | Título |
isbn | string | null | ISBN-13 |
author | string | null | Autor(es) |
publisher | string | null | Editora |
collection | string | null | Origem do título no acervo. Um título pode ter mais de uma linha de acervo; sai a que debita primeiro na ordem de consumo |
hasEbook / hasAudiobook | bool | Formatos disponíveis |
model | int | null | Empréstimos por cópia: max_uses do título, ou 26 quando o título não define. null quando o título só tem Acervo Árvore (ilimitado) |
copies | int | null | Empréstimos possíveis do título: soma de cópias × modelo nas linhas additional, odilo e manual (no Odilo cada cópia vale 1). Apesar do nome, é capacidade em empréstimos, não contagem de cópias. null quando o título só tem Acervo Árvore |
consumedCopies | int | null | Empréstimos confirmados (active) do título desde 2026-07-21 |
availableCopies | int | null | copies − consumedCopies, nunca negativo |
loans / returns / readings10 / readings50 / renewals | int | Métricas do título no período |
readingSeconds | int | Tempo lido no título no período |
reservations / convertedReservations | int | Reservas feitas/convertidas no período |
activeReservations | int | Reservas ativas agora |
datasets/stock
Sem período: é a foto atual do estoque. Parâmetros: purchasedFrom/purchasedTo (data da compra), consumptionBand (faixa do histograma, ex. 1-10), search, publisherId, categoryId, subjectId, collection (additional | odilo | manual; stock não aceita all nem platform, que não têm estoque próprio), bookId, publicationYear, orderBy (title | activeLoans | readings | possibleReadings | percentage | activeReservations, default percentage), orderDir (default desc), page/pageSize. Desempate por título e bookId.
| Campo | Tipo | Descrição |
|---|---|---|
bookId | int | Identificador do título |
title | string | Título |
activeLoans | int | Empréstimos ativos do título agora |
readings | int | Leituras confirmadas (10% do livro) de leitores com empréstimo do título desde 2026-07-21 |
possibleReadings | int | Soma de purchases[].possibleReadings, compras e legado |
percentage | frac | readings ÷ possibleReadings. Passa de 1 com frequência e não é um teto de 100%: readings conta toda leitura confirmada do título, inclusive as servidas pelo Acervo Árvore (ilimitado), enquanto possibleReadings só soma o estoque próprio do título. Um título com 72 leituras e 1 leitura possível sai com 72 |
activeReservations | int | Reservas ativas do título agora |
purchases[].purchaseId | string | "Compra N" para compra no Marketplace; "Legado N" para linha de acervo herdada (odilo ou manual) com cópias |
purchases[].modality | string | null | Modalidade comercial, ex. "Medido" |
purchases[].model | int | Leituras por cópia: max_uses do título, ou 26 quando não define |
purchases[].copies | int | null | Cópias compradas; null nas linhas de legado |
purchases[].possibleReadings | int | Cópias × modelo. No legado Odilo cada cópia vale 1 leitura |
purchases[].consumed | int | Leituras alocadas a esta linha. O consumo do título é distribuído na ordem de purchasedAt: a linha mais antiga enche primeiro, e a seguinte só recebe o que sobrou |
purchases[].percentage | frac | consumed ÷ possibleReadings desta linha. Entre 0 e 1: o consumo alocado nunca passa do possível da linha |
purchases[].purchasedAt | date | Data da compra. Legado anterior a 2026-07-21 sai como 2026-07-21 |
purchases[].unitPrice | money | Preço unitário da cópia; "0" no legado |
purchases[].totalPrice | money | Valor total da compra; "0" no legado |
purchases[].expiresAt | date | null | Expiração da licença, quando houver. Legado com expiração anterior a 2026 sai null |
datasets/loans
Parâmetros: startDate/endDate (sobre a data do empréstimo), userId, bookId, status (active | returned | expired), page/pageSize. Ordenação fixa: data do empréstimo e loanId, ascendentes.
| Campo | Tipo | Descrição |
|---|---|---|
loanId | int | Identificador do empréstimo (idempotência na ingestão) |
userId | int | Leitor. Detalhe no /users |
bookId | int | Título emprestado |
title | string | Título (desnormalizado) |
isbn | string | null | ISBN-13 |
author | string | null | Autor(es) |
borrowedAt | date | null | Data da retirada |
dueAt | date | null | Data prevista de devolução |
returnedAt | date | null | Data efetiva da devolução ou expiração |
status | enum | active em curso · returned devolvido · expired expirou no prazo. active cobre dois estados internos: o empréstimo recém-feito, ainda sem leitura iniciada, e o já confirmado pela abertura do livro |
readingSeconds | int | Tempo lido pelo leitor neste título, acumulado em todos os empréstimos dele |
progress | percent | Maior percentual do livro alcançado pelo leitor neste título, de 0 a 100 (99.32 = 99,32% do livro). Não é fração: não multiplique por 100 |
A fonte não registra leitura por empréstimo individual nem o formato (ebook ou audiobook) escolhido no empréstimo. readingSeconds e progress são do par leitor × título; quem emprestou o mesmo livro duas vezes vê o mesmo valor nas duas linhas.
datasets/reservations
Ciclo completo da reserva, não só a fila ativa. Parâmetros: startDate/endDate (sobre reservedAt), status, userId, bookId, page/pageSize. Ordenação fixa: reservedAt e reservationId, ascendentes.
| Campo | Tipo | Descrição |
|---|---|---|
reservationId | int | Identificador da reserva |
userId | int | Leitor. Detalhe no /users |
bookId | int | Título reservado |
title | string | Título (desnormalizado) |
isbn | string | null | ISBN-13 |
status | enum | waiting aguardando na fila · available exemplar liberado · converted virou empréstimo · cancelled cancelada · lost expirou sem retirada |
position | int | null | Posição na fila. Só enquanto waiting ou available |
titleQueue | int | Tamanho atual da fila do título (foto do sync), na mesma régua do painel: leitores da BibliON, reservas a partir de 2026-07-21 |
reservedAt | date | Data da reserva |
resolvedAt | date | null | Data em que converteu, cancelou ou expirou. É a última alteração do registro, aproximação da data do evento |
datasets/logins
Uma linha por leitor por dia em que ele teve qualquer atividade na plataforma (abrir a BibliON, navegar, ler, emprestar). É a mesma régua do logins do /summary e do /engagements: somando as linhas de um dia, bate com o data.general.logins desse dia. Parâmetros: startDate/endDate (default últimos 30 dias, máximo 31 dias), userId, page/pageSize. Ordenação fixa: date e userId, ascendentes. (date, userId) é chave única.
| Campo | Tipo | Descrição |
|---|---|---|
userId | int | Leitor. Detalhe no /users |
date | date | Dia da atividade |
firstSeenAt | datetime | Primeiro evento do leitor no dia |
lastSeenAt | datetime | Último evento do leitor no dia |
events | int | Quantidade de eventos do leitor no dia |
A plataforma não registra o login como evento próprio (a BibliON entra por link e SSO), por isso o grão é o dia com atividade e não a autenticação. A fonte também não registra o aparelho por leitor; a visão de aparelhos é a do dataset channels.
datasets/channels
Sessões por dia e aparelho, medidas pela ferramenta de analytics. Parâmetros: startDate/endDate (máximo 31 dias), channel. Não é paginado: vem a série inteira do período (page e pageSize são ignorados). Se o analytics não responder, a rota responde 503 e nada fica em cache; basta repetir a chamada depois.
| Campo | Tipo | Descrição |
|---|---|---|
date | date | Dia de referência |
channel | enum | web-mobile | web-desktop | web-tablet | app |
sessions | int | Sessões do canal no dia |
estimated | bool | true nas linhas de app: contagem estimada pela faixa de ids de cadastro da BibliON |
datasets/suggestions
Sugestões de compra agregadas por título. Parâmetros: startDate/endDate, search, page/pageSize.
| Campo | Tipo | Descrição |
|---|---|---|
title | string | null | Título sugerido |
author | string | null | Autor |
publisher | string | null | Editora |
searchTerm | string | null | Termo buscado pelo leitor quando não achou o título |
requestsCount | int | Total de solicitações no período |
uniqueUsers | int | Leitores distintos que solicitaram |
availability | enum | catalog já no acervo · marketplace disponível para compra · none não encontrado |
lastRequestedAt | date | Última solicitação |
datasets/suggestion-requests
Cada solicitação individual. Parâmetros: startDate/endDate, title e author (comparação exata, ignorando maiúsculas e espaços nas pontas), userId, page/pageSize. Ordenação fixa: data e hora do pedido ascendentes, com desempate pelo id interno do pedido, então a paginação é estável durante a ingestão.
| Campo | Tipo | Descrição |
|---|---|---|
userId | int | Leitor que pediu. Detalhe no /users |
title | string | null | Título pedido |
author | string | null | Autor |
searchTerm | string | null | Termo buscado, quando não indicou título |
requestedAt | date | Data do pedido |
GET /libraries/v1/dimensions
Vocabulários válidos para os filtros das demais rotas. Sem parâmetros.
| Campo | Tipo | Descrição |
|---|---|---|
libraries[] | array | { id: string, name: string }. Usar o id (como inteiro) em libraryId |
ageGroups[] | array | { id, name }. Usar em ageGroupId |
publishers[] | array | { id, name }. Usar em publisherId |
categories[] | array | { id, name }. Usar em categoryId |
subjects[] | array | { id, name }. Usar em subjectId |
ras[] | string[] | Regiões administrativas presentes na base. Sem filtro correspondente na v1: serve para conferência, não para recorte |
states[] | string[] | UFs presentes na base |
cities[] | string[] | Cidades presentes na base |
genders[] | string[] | Gêneros canônicos |
publicationYears[] | int[] | Anos de publicação presentes no acervo |
Erros
Corpo de erro padrão: { "statusCode": int, "error": string, "message": string | string[] }. Em erros de validação (400), message é uma lista com uma mensagem por parâmetro inválido.
| HTTP | Quando |
|---|---|
400 | Parâmetro inválido: data mal formatada ou inexistente no calendário, janela acima de 31 dias, enum desconhecido, orderBy ou collection fora da lista, page ou pageSize acima do máximo, ou parâmetro que não existe na rota (property X should not exist) |
503 | Fonte externa fora do ar (só datasets/channels). Repetir depois |
401 | Chave de API ausente ou inválida |
404 | Dataset desconhecido em /datasets/{name} |
429 | Rate limit excedido. Reenviar após o intervalo em Retry-After |
500 | Falha interna; nenhum dado parcial é devolvido |
Ingestão incremental (sugestão)
- Leitores: uma carga inicial paginada de
/userse depois/users?updatedSince=<ontem>por dia. A alteração de status (desativação, exclusão) atualiza o registro e entra no recorte. - Engajamento:
/engagements?startDate=<dia>&endDate=<dia>por dia, paginando atétotalRows. A chave natural é(date, userId). - Empréstimos e reservas:
datasets/loansedatasets/reservationspelo período de criação; a chave éloanId/reservationId. Como o status muda depois da criação, reprocessar os últimos 60 dias cobre devoluções, expirações e conversões. - Agregados:
/summaryuma vez por dia com o período desejado, para conferência dos totais.
Fora do escopo
A aba Radar do painel (detectores, mapa de demanda, ações) não é exposta pela API. Aparelho amarrado a login individual não faz parte da v1; a visão de aparelhos é agregada, via dataset channels.