# Autenticação
Source: https://docs.base39.com.br/api-reference/authentication
A API da Base39 utiliza o protocolo OAuth 2.0 para autenticação e autorização. Este documento explica como implementar a autenticação em sua aplicação.
## O que é OAuth 2.0?
OAuth 2.0 é um protocolo de autorização que permite que aplicações terceiras acessem recursos protegidos em nome de um usuário, sem precisar compartilhar suas credenciais. É o padrão da indústria para autenticação segura.
## Fluxo de autenticação
A Base39 utiliza o Client Credentials Flow, ideal para comunicação entre máquinas/serviços (M2M) onde não há interação do usuário. O processo é simples:
1. **Obtenção de Credenciais**: Sua aplicação usa suas credenciais (Client ID e Client Secret)
2. **Solicitação de Token**: Faz uma requisição direta para obter o token de acesso
3. **Acesso à API**: Use o token para fazer requisições à API
## Implementação
### 1. Registrar sua aplicação
Antes de começar, você precisa registrar sua aplicação com o time de suporte da Base39 para obter:
* Client ID
* Client Secret
### 2. Configurar URLs
* URL de Token: `https://auth.base39.com.br/oauth2/token`
### 3. Escopos disponíveis
* `read`: Permissão para ler dados
* `write`: Permissão para escrever dados
### 4. Exemplo de implementação
```javascript theme={null}
// Obter token diretamente com credenciais
const tokenResponse = await fetch("https://auth.base39.com.br/oauth2/token", {
method: "POST",
headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
body: new URLSearchParams({
grant_type: "client_credentials",
client_id: "SEU_CLIENT_ID",
client_secret: "SEU_CLIENT_SECRET",
scope: "read write",
}),
});
const { access_token } = await tokenResponse.json();
// Usar o token nas requisições
const apiResponse = await fetch("https://api.base39.com.br/v1/...", {
headers: {
Authorization: `Bearer ${access_token}`,
},
});
```
## Segurança
* Nunca compartilhe seu Client Secret
* Sempre use HTTPS
* Armazene tokens de forma segura
* Implemente refresh tokens para renovação automática
* Revogue tokens quando não forem mais necessários
* Use credenciais específicas para cada serviço
* Monitore e audite o uso das credenciais
# Criar relatório
Source: https://docs.base39.com.br/api-reference/endpoint/create-report
POST /reports
Cria um novo relatório com base em um template
# Listar relatórios
Source: https://docs.base39.com.br/api-reference/endpoint/list-reports
GET /reports
Lista todos os relatórios
# Iniciar pesquisar
Source: https://docs.base39.com.br/api-reference/endpoint/run-report
POST /reports/{id}/run
Inicia a execução/pesquisa de um relatório
# Pesquisar registros
Source: https://docs.base39.com.br/api-reference/endpoint/search
POST /projects/{project}/tables/{table}/records/search
Pesquisa linhas na base de dados usando filtros exatos
# Webhook de entrada
Source: https://docs.base39.com.br/api-reference/endpoint/webhook
POST /sources/webhook/{webhook}
Endpoint para recebimento de dados via webhook
# Visão geral
Source: https://docs.base39.com.br/api-reference/files/overview
Envie documentos e receba dados estruturados automaticamente
## Como funciona
Ao enviar um documento, a Base39 lê o conteúdo, identifica o tipo e extrai os dados em formato JSON.
```mermaid theme={null}
flowchart LR
A[Upload] --> B[Leitura]
B --> C[Classificação]
C --> D[Extração]
D --> E[JSON]
```
## Etapas do processamento
O arquivo é enviado usando uma URL temporária fornecida pela API
O conteúdo do documento é lido e interpretado
O sistema reconhece o tipo de documento (balanço, DRE, nota fiscal, etc.)
Os dados são extraídos e organizados em JSON
## Formatos aceitos
| Extensão | Processamento |
| -------------------------------- | ----------------- |
| `.pdf` | Leitura completa |
| `.png`, `.jpg`, `.jpeg`, `.tiff` | Leitura de imagem |
| `.txt`, `.csv`, `.tsv` | Leitura direta |
## Templates disponíveis
Cada tipo de documento possui extração especializada:
Ativos, passivos e patrimônio líquido
Demonstração de resultados (em breve)
## Status do processamento
| Status | Significado |
| ------------- | ------------------------------ |
| `not_started` | Tipo de arquivo não processado |
| `pending` | Aguardando na fila |
| `processing` | Leitura em andamento |
| `completed` | Concluído com sucesso |
| `failed` | Falha no processamento |
## Exemplo de resposta
```json theme={null}
{
"object": "file_upload",
"id": "fu_abc123",
"status": "uploaded",
"filename": "balanco_2024.pdf",
"parsing": {
"status": "completed",
"template": "balance_sheet",
"confidence": 0.95
},
"parsed_data": {}
}
```
## Próximos passos
Como fazer upload
Consultar status do processamento
# Leitura de documentos
Source: https://docs.base39.com.br/api-reference/files/parsing
Acompanhe o processamento e acesse os dados extraídos
## Como funciona
Após o upload, o arquivo passa por três etapas:
1. **Leitura** do conteúdo do documento
2. **Classificação** do tipo (balanço, DRE, nota fiscal, etc.)
3. **Extração** dos dados em formato JSON
## Consultar status
```
GET /v2/file_uploads/:id
```
### Resposta
```json theme={null}
{
"object": "file_upload",
"id": "fu_abc123",
"status": "uploaded",
"parsing": {
"status": "completed",
"template": "balance_sheet",
"confidence": 0.95,
"started_time": "2024-12-07T11:01:00.000Z",
"completed_time": "2024-12-07T11:02:30.000Z"
},
"parsed_data": {}
}
```
## Campos retornados
| Campo | Tipo | Descrição |
| ------------------------ | ------ | ------------------------------------------- |
| `parsing.status` | string | Status atual do processamento |
| `parsing.template` | string | Template identificado (ex: `balance_sheet`) |
| `parsing.confidence` | number | Confiança da Classificação (0 a 1) |
| `parsing.started_time` | string | Início do processamento |
| `parsing.completed_time` | string | Fim do processamento |
| `parsing.error` | string | Mensagem de erro, se houver |
## Templates disponíveis
| Template | Tipo de documento | Disponibilidade |
| ------------------ | ------------------- | --------------- |
| `balance_sheet` | Balanço patrimonial | Disponível |
| `income_statement` | DRE | Em breve |
| `invoice` | Notas fiscais | Em breve |
| `no_template` | Outros documentos | Disponível |
## Aguardar processamento
O tempo varia de **30 segundos a 15 minutos**, dependendo do tamanho do
documento.
Exemplo de polling até a conclusão:
```javascript theme={null}
async function waitForProcessing(fileId, token, maxAttempts = 30) {
for (let i = 0; i < maxAttempts; i++) {
const response = await fetch(
`https://api.base39.com.br/v2/file_uploads/${fileId}`,
{
headers: { Authorization: `Bearer ${token}` },
}
);
const data = await response.json();
if (data.parsing.status === "completed") {
return data;
}
if (data.parsing.status === "failed") {
throw new Error(data.parsing.error);
}
await new Promise((r) => setTimeout(r, 2000));
}
throw new Error("Timeout");
}
```
## Acessar dados extraídos
Após o processamento, o JSON estruturado pode ser baixado:
```javascript theme={null}
const fileUpload = await waitForProcessing(fileId, token);
if (fileUpload.parsed_data) {
const response = await fetch(fileUpload.parsed_data);
const data = await response.json();
// Acessar primeira empresa e período
const company = data.companies[0];
const period = company.periods[0];
console.log("Empresa:", company.company_name);
console.log("Ativo total:", period.assets.value);
console.log("Passivo total:", period.liabilities.value);
console.log("Patrimônio Líquido:", period.equity.value);
}
```
# Balanço Patrimonial
Source: https://docs.base39.com.br/api-reference/files/templates/balance-sheet
Schema do template balance_sheet
## Schema
O template `balance_sheet` extrai dados estruturados de balanços patrimoniais.
Suporta múltiplas empresas, múltiplos períodos por arquivo e demonstrações individuais/consolidadas.
```json theme={null}
{
"companies": [
{
"company_name": "ACME LTDA",
"company_document": "12.345.678/0001-90",
"statement_type": "individual",
"periods": [
{
"reference_date": "2024-12-31",
"assets": {
"description": "ATIVO",
"value": 1000000,
"code": "1",
"children": [
{
"description": "ATIVO CIRCULANTE",
"value": 600000,
"code": "1.1",
"children": [
{
"description": "Caixa",
"value": 50000,
"code": "1.1.1.01"
},
{
"description": "Bancos",
"value": 550000,
"code": "1.1.1.02"
}
]
},
{
"description": "ATIVO NÃO CIRCULANTE",
"value": 400000,
"code": "1.2",
"children": [
{
"description": "Veículos",
"value": 500000,
"code": "1.2.3.04"
},
{
"description": "(-) Depreciação",
"value": -100000,
"code": "1.2.3.06"
}
]
}
]
},
"liabilities": {
"description": "PASSIVO",
"value": 600000,
"code": "2.1",
"children": [
{
"description": "Fornecedores",
"value": 400000,
"code": "2.1.2.01"
},
{
"description": "Empréstimos",
"value": 200000,
"code": "2.1.3.01"
}
]
},
"equity": {
"description": "PATRIMÔNIO LÍQUIDO",
"value": 400000,
"code": "2.3",
"children": [
{
"description": "Capital Social",
"value": 300000,
"code": "2.3.1.01"
},
{
"description": "Lucros Acumulados",
"value": 100000,
"code": "2.3.3.01"
}
]
}
}
]
}
]
}
```
**Observações:**
* Valores são sempre expressos em unidades (R\$). Se o documento original estiver em milhares, os valores são convertidos.
* Para balanços com demonstração individual e consolidada, cada uma é representada como entrada separada em `companies[]` com `statement_type` diferente.
## Campos
### CompanyBalanceSheet
| Campo | Tipo | Descrição |
| ------------------ | --------- | ---------------------------------- |
| `company_name` | string | Nome da empresa |
| `company_document` | string? | CNPJ formatado |
| `statement_type` | string? | `"individual"` ou `"consolidated"` |
| `periods` | Period\[] | Lista de períodos |
### Period
| Campo | Tipo | Descrição |
| ---------------- | ----------- | ------------------------------------------ |
| `reference_date` | string | Data de referência do balanço (YYYY-MM-DD) |
| `assets` | AccountNode | Árvore do Ativo |
| `liabilities` | AccountNode | Árvore do Passivo |
| `equity` | AccountNode | Árvore do PL |
### AccountNode
| Campo | Tipo | Descrição |
| ------------- | --------------- | -------------------------------------- |
| `description` | string | Descrição da conta |
| `value` | number | Valor em R\$ (negativo para redutoras) |
| `code` | string? | Código contábil |
| `note` | string? | Nota explicativa |
| `children` | AccountNode\[]? | Subcontas |
## Códigos contábeis
Os códigos seguem as normas brasileiras de contabilidade emitidas pelo CFC (Conselho Federal de Contabilidade):
* **ITG 1000** - Interpretação Técnica Geral para microempresas e empresas de pequeno porte
* **NBC TG 1001/1002** - Normas Brasileiras de Contabilidade para microentidades e pequenas empresas
* **NBC TG 1000** - Contabilidade para Pequenas e Médias Empresas (equivalente ao IFRS for SMEs)
* **CPC/IFRS** - Pronunciamentos do Comitê de Pronunciamentos Contábeis, convergentes com as normas internacionais IFRS (International Financial Reporting Standards)
### Microempresas e EPPs (ITG 1000)
Empresas com receita bruta anual ≤ R\$ 78 milhões (NBC TG 1001/1002 e ITG 1000)
#### Ativo Circulante (1.1.x)
| Código | Descrição |
| ---------- | --------------------------------------------- |
| `1.1.1.01` | Caixa |
| `1.1.1.02` | Bancos Conta Movimento |
| `1.1.1.03` | Aplicações Financeiras |
| `1.1.1.04` | Títulos e Valores Mobiliários |
| `1.1.1.05` | Instrumentos Financeiros Derivativos |
| `1.1.2.01` | Clientes |
| `1.1.2.02` | (-) PECLD |
| `1.1.2.03` | Adiantamento a Fornecedores |
| `1.1.2.04` | Tributos a Recuperar |
| `1.1.2.05` | Partes Relacionadas - No País |
| `1.1.2.06` | Partes Relacionadas - No Exterior |
| `1.1.2.07` | AFAC (Adiantamento p/ Futuro Aumento Capital) |
| `1.1.2.08` | Adiantamentos de Clientes (quando ativo) |
| `1.1.3.01` | Mercadorias para Revenda |
| `1.1.3.02` | Produtos Acabados |
| `1.1.3.03` | Insumos/Matéria-Prima |
| `1.1.4.01` | Despesas Antecipadas |
#### Ativo Não Circulante (1.2.x)
| Código | Descrição |
| ---------- | -------------------------------- |
| `1.2.1.01` | Realizável a Longo Prazo |
| `1.2.1.02` | Títulos e Valores Mobiliários LP |
| `1.2.1.03` | AFAC - Longo Prazo |
| `1.2.1.04` | Partes Relacionadas LP |
| `1.2.2.01` | Participações Societárias |
| `1.2.3.01` | Terrenos |
| `1.2.3.02` | Edificações |
| `1.2.3.03` | Máquinas e Equipamentos |
| `1.2.3.04` | Veículos |
| `1.2.3.05` | Móveis e Utensílios |
| `1.2.3.06` | (-) Depreciação Acumulada |
| `1.2.4.01` | Softwares |
| `1.2.4.02` | (-) Amortização Acumulada |
#### Passivo Circulante (2.1.x)
| Código | Descrição |
| ---------- | ------------------------------------ |
| `2.1.1.01` | Salários a Pagar |
| `2.1.1.02` | INSS a Recolher |
| `2.1.1.03` | FGTS a Recolher |
| `2.1.1.04` | Provisão de Férias |
| `2.1.1.05` | Provisão de 13º Salário |
| `2.1.2.01` | Fornecedores |
| `2.1.2.02` | Aluguéis a Pagar |
| `2.1.3.01` | Empréstimos Bancários |
| `2.1.3.02` | Financiamentos |
| `2.1.4.01` | IRPJ a Recolher |
| `2.1.4.02` | CSLL a Recolher |
| `2.1.4.03` | PIS a Recolher |
| `2.1.4.04` | COFINS a Recolher |
| `2.1.4.05` | ICMS a Recolher |
| `2.1.4.06` | ISS a Recolher |
| `2.1.4.07` | Simples Nacional |
| `2.1.5.01` | Dividendos a Pagar |
| `2.1.5.02` | Instrumentos Financeiros Derivativos |
| `2.1.5.03` | Partes Relacionadas - Circulante |
| `2.1.5.04` | Adiantamentos de Clientes |
#### Passivo Não Circulante (2.2.x)
| Código | Descrição |
| ---------- | ---------------------- |
| `2.2.1.01` | Empréstimos LP |
| `2.2.1.02` | Financiamentos LP |
| `2.2.2.01` | Tributos Parcelados |
| `2.2.2.02` | Partes Relacionadas LP |
#### Patrimônio Líquido (2.3.x)
| Código | Descrição |
| ---------- | --------------------------------------------- |
| `2.3.1.01` | Capital Social Subscrito |
| `2.3.1.02` | (-) Capital a Integralizar |
| `2.3.1.03` | AFAC (Adiantamento p/ Futuro Aumento Capital) |
| `2.3.2.01` | Reservas de Capital |
| `2.3.2.02` | Reservas de Lucros |
| `2.3.2.03` | Ajustes de Avaliação Patrimonial |
| `2.3.3.01` | Lucros Acumulados |
| `2.3.3.02` | (-) Prejuízos Acumulados |
| `2.3.3.03` | Resultado do Exercício |
### Médias Empresas (NBC TG 1000)
Empresas com receita bruta anual > R$ 78 milhões e ≤ R$ 300 milhões
Utiliza a mesma estrutura das micro/pequenas empresas, com contas adicionais:
#### Contas Adicionais - Ativo
| Código | Descrição |
| ---------- | ------------------------------------------------------- |
| `1.2.2.02` | Ágio por Expectativa de Rentabilidade Futura (Goodwill) |
| `1.2.3.07` | Propriedades para Investimento |
| `1.2.3.08` | (-) Depreciação Prop. Investimento |
#### Contas Adicionais - Patrimônio Líquido
| Código | Descrição |
| ---------- | ------------- |
| `2.3.2.04` | Reserva Legal |
### Grandes Empresas/Capital Aberto (CPC/IFRS)
Empresas com receita bruta > R\$ 300 milhões ou S.A. de capital aberto
Utiliza a estrutura completa CPC/IFRS com contas adicionais:
#### Contas Adicionais - Ativo
| Código | Descrição |
| ---------- | --------------------------------- |
| `1.2.2.03` | Investimentos em Controladas |
| `1.2.2.04` | Investimentos em Coligadas |
| `1.2.2.05` | Investimentos em Joint Ventures |
| `1.2.3.09` | Ativos de Direito de Uso (CPC 06) |
| `1.2.3.10` | (-) Depreciação Direito de Uso |
| `1.2.4.03` | Marcas |
| `1.2.4.04` | Patentes e Segredos Industriais |
#### Contas Adicionais - Passivo
| Código | Descrição |
| ---------- | --------------------------------- |
| `2.1.5.05` | Arrendamentos a Pagar CP (CPC 06) |
| `2.2.3.01` | Arrendamentos a Pagar LP (CPC 06) |
| `2.2.4.01` | Provisões para Contingências |
| `2.2.4.02` | Tributos Diferidos |
#### Contas Adicionais - Patrimônio Líquido
| Código | Descrição |
| ---------- | ----------------------------- |
| `2.3.2.05` | Outros Resultados Abrangentes |
| `2.3.2.06` | Ações em Tesouraria |
## Exemplo de Uso
```javascript theme={null}
const balanceSheet = await response.json();
// Percorrer árvore
function walk(node, depth = 0) {
const note = node.note ? ` (Nota ${node.note})` : "";
console.log(" ".repeat(depth) + node.description + ": " + node.value + note);
(node.children || []).forEach((c) => walk(c, depth + 1));
}
// Listar contas
balanceSheet.companies.forEach((company) => {
const type = company.statement_type || "individual";
console.log(`${company.company_name} (${type})`);
company.periods.forEach((period) => {
console.log(` Data: ${period.reference_date}`);
walk(period.assets, 2);
});
});
// Buscar por código
function findByCode(node, code) {
if (node.code === code) return node;
for (const child of node.children || []) {
const found = findByCode(child, code);
if (found) return found;
}
return null;
}
const caixa = findByCode(
balanceSheet.companies[0].periods[0].assets,
"1.1.1.01"
);
```
# Enviar arquivos
Source: https://docs.base39.com.br/api-reference/files/upload
Faça upload de documentos para extração automática de dados
## Criar upload
Após o envio, o arquivo é processado automaticamente. Nenhuma configuração adicional é necessária.
### Endpoint
```
POST /v2/file_uploads
```
### Requisição
```bash theme={null}
curl -X POST https://api.base39.com.br/v2/file_uploads \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_TOKEN" \
-d '{
"filename": "balanco_2024.pdf",
"content_type": "application/pdf"
}'
```
### Resposta
```json theme={null}
{
"object": "file_upload",
"id": "fu_abc123def456",
"status": "pending",
"filename": "balanco_2024.pdf",
"content_type": "application/pdf",
"upload_url": "https://s3.amazonaws.com/bucket/...?X-Amz-Signature=...",
"expires_at": "2024-12-07T12:00:00.000Z",
"parsing": {
"status": "not_started"
}
}
```
## Enviar o arquivo
Use a `upload_url` retornada para enviar o conteúdo do arquivo via PUT:
```bash theme={null}
curl -X PUT "https://s3.amazonaws.com/bucket/...?X-Amz-Signature=..." \
-H "Content-Type: application/pdf" \
--data-binary @/caminho/do/arquivo.pdf
```
A URL expira em **1 hora**. O arquivo deve ser enviado logo após criar o upload.
## Exemplo completo em JavaScript
```javascript theme={null}
async function uploadFile(file) {
// Criar upload e obter URL
const response = await fetch('https://api.base39.com.br/v2/file_uploads', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: 'Bearer YOUR_TOKEN',
},
body: JSON.stringify({
filename: file.name,
content_type: file.type,
}),
})
const { id, upload_url } = await response.json()
// Enviar arquivo para S3
await fetch(upload_url, {
method: 'PUT',
headers: { 'Content-Type': file.type },
body: file,
})
// Aguardar processamento
let fileUpload
do {
await new Promise((r) => setTimeout(r, 2000))
const res = await fetch(`https://api.base39.com.br/v2/file_uploads/${id}`, {
headers: { Authorization: 'Bearer YOUR_TOKEN' },
})
fileUpload = await res.json()
} while (fileUpload.parsing.status === 'pending' || fileUpload.parsing.status === 'processing')
return fileUpload
}
// Uso
const file = document.querySelector('input[type="file"]').files[0]
const result = await uploadFile(file)
if (result.parsing.status === 'completed') {
console.log('Template:', result.parsing.template)
console.log('Dados:', result.parsed_data)
}
```
## Exemplo em Python
```python theme={null}
import requests
import time
def upload_file(file_path: str, token: str):
# Criar upload
with open(file_path, 'rb') as f:
filename = file_path.split('/')[-1]
content_type = 'application/pdf'
response = requests.post(
'https://api.base39.com.br/v2/file_uploads',
headers={
'Authorization': f'Bearer {token}',
'Content-Type': 'application/json'
},
json={
'filename': filename,
'content_type': content_type
}
)
data = response.json()
file_id = data['id']
upload_url = data['upload_url']
# Enviar arquivo
f.seek(0)
requests.put(
upload_url,
headers={'Content-Type': content_type},
data=f
)
# Aguardar processamento
while True:
time.sleep(2)
response = requests.get(
f'https://api.base39.com.br/v2/file_uploads/{file_id}',
headers={'Authorization': f'Bearer {token}'}
)
file_upload = response.json()
if file_upload['parsing']['status'] not in ['pending', 'processing']:
break
return file_upload
# Uso
result = upload_file('/caminho/para/balanco.pdf', 'YOUR_TOKEN')
print(f"Template: {result['parsing']['template']}")
```
## Parâmetros
| Campo | Tipo | Obrigatório | Descrição |
| -------------- | ------ | ----------- | -------------------------------------- |
| `filename` | string | Sim | Nome do arquivo (máx. 900 caracteres) |
| `content_type` | string | Sim | Tipo MIME do arquivo |
| `size_bytes` | number | Não | Tamanho em bytes para validação prévia |
## Limites de tamanho
| Plano | Máximo por arquivo |
| ----- | ------------------ |
| Free | 5 MB |
| Paid | 5 GB |
# Entendendo as Seções dos Relatórios
Source: https://docs.base39.com.br/api-reference/sections-structure
Como interpretar e usar as seções que compõem os relatórios gerados
## O que são Seções?
Quando você cria um relatório através da API, ele é dividido em **seções** (sections). Cada seção representa uma parte específica do relatório, como "Resumo Executivo", "Análise Financeira", ou "Conclusão".
As seções são geradas de forma **assíncrona** - você receberá o relatório imediatamente, mas o conteúdo das seções será processado em segundo plano pela nossa IA.
## Estrutura de uma Seção
Cada seção contém as seguintes informações:
| Campo | Tipo | Descrição |
| --------- | ------ | ---------------------------------------- |
| `id` | string | Identificador único da seção |
| `title` | string | Título/nome da seção |
| `status` | string | Status do processamento (veja abaixo) |
| `order` | number | Ordem da seção no relatório (1, 2, 3...) |
| `content` | string | Conteúdo gerado pela IA (texto) |
### Status das Seções
Uma seção pode ter os seguintes status:
| Status | Significado | O que fazer |
| ------------ | -------------------------- | ------------------------------------- |
| `queued` | Na fila para processamento | Aguarde, será processada em breve |
| `processing` | Sendo gerada pela IA | Aguarde, o conteúdo está sendo criado |
| `done` | Concluída com sucesso | O conteúdo está pronto em `content` |
| `error` | Erro no processamento | Verifique logs ou tente novamente |
## Exemplo Prático
```json theme={null}
{
"id": "rep_xyz789",
"status": "processing",
"sections": [
{
"id": "sec_abc123",
"title": "Resumo Executivo",
"status": "done",
"order": 1,
"content": "Este relatório apresenta uma análise completa da Empresa XYZ. Principais pontos: ..."
},
{
"id": "sec_def456",
"title": "Análise Financeira",
"status": "processing",
"order": 2,
"content": null
},
{
"id": "sec_ghi789",
"title": "Conclusão",
"status": "queued",
"order": 3,
"content": null
}
]
}
```
Neste exemplo:
* ✅ Primeira seção está **pronta** e você pode usar o conteúdo
* ⏳ Segunda seção está sendo **processada**
* ⏸️ Terceira seção está na **fila** aguardando
## Como Usar as Seções
### 1. Criar um Relatório
```bash theme={null}
POST /reports
{
"target": {
"document": "12345678901"
},
"template": "tpl_abc123"
}
```
**Resposta:**
```json theme={null}
{
"id": "rep_xyz789",
"sections": [
{
"id": "sec_abc123",
"title": "Resumo Executivo",
"status": "queued",
"order": 1,
"content": null
}
]
}
```
### 2. Verificar o Progresso
Para ver se as seções foram processadas, faça uma nova requisição GET:
```bash theme={null}
GET /reports/rep_xyz789
```
**Resposta:**
```json theme={null}
{
"id": "rep_xyz789",
"status": "completed",
"sections": [
{
"id": "sec_abc123",
"title": "Resumo Executivo",
"status": "done",
"order": 1,
"content": "Análise completa da empresa..."
}
]
}
```
### 3. Reprocessar Seções
Se precisar gerar novamente o conteúdo de um relatório:
```bash theme={null}
POST /reports/rep_xyz789/run
```
Isso iniciará um novo processamento de todas as seções.
## Monitoramento em Tempo Real
### Polling (Recomendado)
Faça requisições periódicas para verificar o status:
```javascript theme={null}
async function waitForReport(reportId) {
while (true) {
const response = await fetch(`https://api.base39.com.br/v1/reports/${reportId}`);
const report = await response.json();
// Verifica se todas as seções estão prontas
const allDone = report.sections.every(s => s.status === 'done');
if (allDone) {
return report;
}
// Aguarda 5 segundos antes de verificar novamente
await new Promise(resolve => setTimeout(resolve, 5000));
}
}
```
### Webhooks (Futuro)
Em breve, você poderá configurar webhooks para receber notificações quando as seções forem concluídas.
## Boas Práticas
### ✅ Faça
* **Verifique o status** antes de usar o conteúdo
* **Implemente retry** para seções com erro
* **Use polling** com intervalos adequados (5-10 segundos)
* **Processe seções individualmente** conforme ficam prontas
### ❌ Evite
* **Não assuma** que o conteúdo está pronto imediatamente
* **Não faça polling** muito frequente (\< 3 segundos)
* **Não ignore** o campo `status`
* **Não processe** seções com `content: null`
## Tempos Estimados
| Tipo de Seção | Tempo Estimado |
| ------------------ | -------------- |
| Resumo curto | 10-30 segundos |
| Análise média | 30-60 segundos |
| Relatório completo | 1-3 minutos |
Os tempos podem variar dependendo da complexidade da análise e da carga do sistema.
## Exemplos de Código
### Python
```python theme={null}
import requests
import time
def create_and_wait_report(document, template):
# Criar relatório
response = requests.post(
'https://api.base39.com.br/v1/reports',
headers={'Authorization': 'Bearer YOUR_TOKEN'},
json={'target': {'document': document}, 'template': template}
)
report_id = response.json()['id']
# Aguardar conclusão
while True:
response = requests.get(
f'https://api.base39.com.br/v1/reports/{report_id}',
headers={'Authorization': 'Bearer YOUR_TOKEN'}
)
report = response.json()
# Verificar se todas as seções estão prontas
all_done = all(s['status'] == 'done' for s in report['sections'])
if all_done:
return report
time.sleep(5)
# Usar
report = create_and_wait_report('12345678901', 'tpl_abc123')
for section in report['sections']:
print(f"{section['title']}: {section['content'][:100]}...")
```
### JavaScript/TypeScript
```typescript theme={null}
async function createAndWaitReport(document: string, template: string) {
// Criar relatório
const createResponse = await fetch('https://api.base39.com.br/v1/reports', {
method: 'POST',
headers: {
'Authorization': 'Bearer YOUR_TOKEN',
'Content-Type': 'application/json'
},
body: JSON.stringify({
target: { document },
template
})
});
const { id } = await createResponse.json();
// Aguardar conclusão
while (true) {
const response = await fetch(`https://api.base39.com.br/v1/reports/${id}`, {
headers: { 'Authorization': 'Bearer YOUR_TOKEN' }
});
const report = await response.json();
// Verificar se todas as seções estão prontas
const allDone = report.sections.every(s => s.status === 'done');
if (allDone) {
return report;
}
await new Promise(resolve => setTimeout(resolve, 5000));
}
}
// Usar
const report = await createAndWaitReport('12345678901', 'tpl_abc123');
report.sections.forEach(section => {
console.log(`${section.title}:`, section.content.substring(0, 100));
});
```
## Tratamento de Erros
```javascript theme={null}
async function processReport(reportId) {
const report = await getReport(reportId);
for (const section of report.sections) {
switch (section.status) {
case 'done':
// Processar conteúdo
console.log(section.content);
break;
case 'error':
// Tentar reprocessar
console.error(`Erro na seção ${section.title}`);
await retrySection(reportId);
break;
case 'processing':
case 'queued':
// Aguardar
console.log(`Aguardando seção ${section.title}...`);
break;
}
}
}
```
## Perguntas Frequentes
### Por que as seções não estão prontas imediatamente?
As seções são geradas por IA que precisa analisar múltiplas fontes de dados, realizar pesquisas e processar informações. Isso leva alguns segundos a minutos dependendo da complexidade.
### Posso processar apenas algumas seções?
Atualmente, todas as seções são processadas juntas. Em breve, será possível processar seções individualmente.
### O que acontece se houver erro em uma seção?
A seção ficará com `status: "error"`. As outras seções continuarão o processamento normalmente. Você pode tentar reprocessar o relatório completo usando o endpoint `/run`.
### Quanto tempo os relatórios ficam disponíveis?
Os relatórios e suas seções ficam disponíveis indefinidamente na sua conta.
# Webhooks de entrada
Source: https://docs.base39.com.br/incoming-webhooks
Na Base39, você pode importar dados diretamente para uma tabela usando a opção de Webhook por meio de requisições HTTP.
## Passo a passo
1. **Acesse a tabela desejada**\
Vá até a tabela em que você deseja importar os dados.
2. **Clique em "Ações" no canto superior direito**\
Um menu será exibido com várias opções relacionadas à tabela.
3. **Selecione "Importar dados"**\
Essa opção abrirá as possibilidades de importação disponíveis.
4. **Escolha a opção "Webhook"**\
Uma nova coluna será criada para receber os dados. Essa URL é exclusiva dessa coluna.
5. **Copie a URL gerada**\
Essa é a URL para a qual você deverá enviar os dados via requisições HTTP POST.
Você pode consultar novamente a URL clicando na coluna Webhook.
## Formato da requisição
O corpo da requisição deve ser um **objeto JSON com pares chave-valor**, representando os dados que deseja importar.
A chave pode ser:
* **ID da coluna**
* **Nome exato da coluna**
Exemplo de requisição:
```json theme={null}
{
"email": "exemplo@email.com",
"nome": "João Silva",
"f_zmHL6ZWVkZogjCBMYwVMT": "São Paulo"
}
```
## Observações importantes:
* Se uma **chave enviada não corresponder exatamente a nenhuma coluna existente**, uma **nova coluna será criada automaticamente** com o nome fornecido.
* O envio deve ser feito por **requisições HTTP POST** para a URL fornecida.
## Desativar ou excluir uma URL
Se você não quiser mais receber dados por uma URL de Webhook, basta **excluir a coluna vinculada à URL**. Isso desativa imediatamente a URL, impedindo novas importações por aquele endereço.
## Dica
Use esse recurso para conectar a Base39 com CRMs, sistemas internos, formulários ou qualquer outra ferramenta que permita envio de dados por API.