Parceiros

Leitura para redes de escolas

API somente leitura para a rede de escolas puxar, de forma programática, quem são os usuários da rede, em que dias eles acessaram a plataforma e o que leram. Tempo e porcentagem de leitura seguem a mesma régua de leitura efetiva do painel da escola, então os números batem com o que a escola vê lá.

São três rotas, organizadas pelo grão do dado:

RotaGrãoEntrega
GET /schools/v1/users1 linha por usuáriocadastro de alunos e professores
GET /schools/v1/engagementsdia × usuáriodias com acesso e minutos de leitura efetiva
GET /schools/v1/readingsusuário × livroporcentagem lida, minutos e conclusão por livro

Acesso

ItemValor
Hosthttps://livros.arvore.com.br
Base path/api-arvore/schools/v1
AutenticaçãoHeader X-Api-Key: <chave> (alternativa: Authorization: Bearer <chave>). Chave emitida pela Árvore, exclusiva da rede e desta API. Sem chave válida: 401
TenantA chave define a rede. A API nunca aceita identificador de rede do cliente e não devolve dado de outra rede
FormatoJSON UTF-8, somente GET
Rate limit30 requisições por minuto por chave; excedente recebe 429 com header Retry-After

Exemplo:

curl -s \
  -H 'X-Api-Key: <chave>' \
  'https://livros.arvore.com.br/api-arvore/schools/v1/readings?startDate=2026-09-01&endDate=2026-09-30&pageSize=1000'

Convenções e tipos

TipoFormatoExemplo
intinteiro não-negativo1609673
stringtexto UTF-8"Nos porões da Ditadura"
booltrue / falsetrue
dateYYYY-MM-DD, fuso de Brasília (UTC−3)"2026-09-02"
datetimeISO 8601 em UTC"2026-09-02T18:38:17Z"
minutesminutos com uma casa decimal25.5
percentpercentual de 0 a 100, com duas casas56.93
enumum valor do conjunto listado no campo"student"
  • Tempo de leitura é sempre em minutos, com uma casa decimal.
  • Campos sem valor vêm como null, nunca omitidos.
  • O histórico começa em 2026-01-01. Um startDate anterior vira 2026-01-01; um período que termina antes disso responde 400.
  • startDate e endDate são inclusivos, em YYYY-MM-DD, e precisam existir no calendário (2026-02-30 responde 400). Quando omitidos, valem os 30 dias que terminam no endDate (ou hoje). Um endDate no futuro vira hoje. startDate depois de endDate responde 400.
  • userId é o identificador do usuário na Árvore e é a chave que liga as três rotas.

Paginação

page começa em 1 (default 1) e vai até 100000. pageSize tem default 100 e máximo 1000 em todas as rotas; acima disso responde 400. O total de linhas vem em meta.page.totalRows. A ordenação é fixa em cada rota, então paginar em sequência não perde nem repete linha.

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 Escola-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. Cada chamada leva alguns segundos (de 2 a 6 s numa rede de 10 mil usuários com o ano inteiro). Uma carga por dia costuma bastar.

Envelope de resposta

Toda rota responde neste formato. data.rows é o array de linhas.

{
  "meta": {
    "period": { "startDate": "2026-09-01", "endDate": "2026-09-30" },
    "page": { "page": 1, "pageSize": 100, "totalRows": 9317 }
  },
  "data": { "rows": [] }
}
CampoTipoDescrição
meta.period.startDatedateInício efetivo do período consultado (após defaults e ajustes)
meta.period.endDatedateFim efetivo do período
meta.page.*intpage, pageSize, totalRows
data.rowsarrayLinhas da rota

meta.period aparece só em /engagements e /readings.

Leitura efetiva

Tempo e porcentagem de leitura usam a régua do painel da escola. A leitura chega em trechos, e um trecho conta como leitura efetiva quando tem de 5 a 800 palavras por minuto, ou quando não tem velocidade registrada e dura pelo menos 3 segundos. Trechos fora disso (página virada rápido demais, por exemplo) não entram no tempo nem na porcentagem.

A porcentagem de um livro é quanto dele foi coberto pelos trechos efetivos do período, somando os intervalos lidos sem contar duas vezes o que foi relido. Um livro é concluído quando essa porcentagem chega a 50%.

GET /schools/v1/users

Cadastro dos usuários da rede, alunos e professores. É o único lugar da API com dado nominal; as demais rotas referenciam o usuário por userId. Contas internas da Árvore e administradores ficam de fora. Ordenação fixa userId ASC.

Parâmetros

ParamTipoObrigatórioDescrição
userIdintnãoUm usuário específico
schoolIdintnãoFiltra por unidade
profileenumnãostudent | teacher. Default: os dois
page / pageSizeintnãoPaginação (máximo 1000)

data.rows[]

CampoTipoDescrição
userIdintIdentificador do usuário na Árvore
namestring | nullNome
emailstring | nullE-mail
profileenumstudent aluno · teacher professor
schoolobject | nullUnidade: { id: int, name: string | null }
classobject | nullTurma: { id: int, name: string | null }; null para quem não está enturmado, como a maioria dos professores
gradeint | nullAno escolar (1 a 9); null quando a turma não tem ano, como no ensino médio sem série ou na educação infantil
stagestring | nullEtapa: INFANTIL, FUNDAMENTAL 1, FUNDAMENTAL 2 ou MEDIO
activeboolSe a conta está ativa

A unidade e a turma são as atuais do usuário. Cadastros de menores de idade estão na base: quem leva esses dados a outro sistema responde pelo tratamento no destino.

GET /schools/v1/engagements

Uma linha por usuário por dia em que ele acessou a plataforma. Conta como acesso o login, uma sessão aberta ou qualquer atividade no dia (leitura, audiolivro, atividade, avaliação de fluência). Receber uma indicação ou uma atividade sem abrir não conta. Dia sem acesso não gera linha. Ordenação fixa date ASC, userId ASC.

Parâmetros

ParamTipoObrigatórioDescrição
startDate / endDatedatenãoPeríodo (default: 30 dias)
userIdintnãoUm usuário específico
schoolIdintnãoFiltra por unidade
profileenumnãostudent | teacher
page / pageSizeintnãoPaginação (máximo 1000)

data.rows[]

CampoTipoDescrição
datedateDia do acesso
userIdintUsuário
readingMinutesminutesMinutos de leitura efetiva no dia; 0 quando o usuário acessou sem ler

A soma de readingMinutes no período é igual à soma do /readings no mesmo período e filtro.

GET /schools/v1/readings

Uma linha por usuário e livro com leitura efetiva no período. Ordenação fixa userId ASC, book.id ASC.

Parâmetros

ParamTipoObrigatórioDescrição
startDate / endDatedatenãoPeríodo (default: 30 dias)
userIdintnãoUm usuário específico
schoolIdintnãoFiltra por unidade
profileenumnãostudent | teacher
page / pageSizeintnãoPaginação (máximo 1000)

data.rows[]

CampoTipoDescrição
userIdintUsuário
bookobject{ id: int, title: string | null, author: string | null, isbn: string | null }
percentpercentQuanto do livro foi lido de forma efetiva no período
readingMinutesminutesMinutos de leitura efetiva do livro no período
firstReadAtdatetimePrimeiro trecho efetivo no período
lastReadAtdatetimeÚltimo trecho efetivo no período
finishedbooltrue quando percent chega a 50%

percent e finished são do período consultado: um livro lido 30% em setembro e mais 30% em outubro aparece com cerca de 30% em cada mês e com cerca de 60% (concluído) numa consulta de setembro a outubro.

Montar a planilha anual

Para o consolidado aluno × livro do ano, percorra GET /schools/v1/readings?startDate=2026-01-01&endDate=2026-12-31&pageSize=1000&page=N em sequência até meta.page.totalRows, e junte com /users pelo userId para trazer nome, unidade, turma e ano escolar.

Erros

StatusQuando
400Parâmetro inválido: data fora do formato, período que termina antes de 2026, startDate depois de endDate, pageSize acima de 1000, profile fora do conjunto
401Sem chave, ou chave inválida
429Mais de 30 requisições no minuto