# 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.