# Correção da liberação da API por Space Fonte: https://docs.ruralzap.com.br/changelog/2026-10-03-api-access Configurações e consultas respeitam a permissão do plano ou a liberação manual do Space. O card **API e integrações** aparece somente quando o Space atual tem acesso efetivo à API. A habilitação no ambiente exige também a inclusão no plano, ou uma liberação manual vigente por Space; planos sem recursos técnicos configurados não recebem acesso automaticamente. O administrador do ambiente pode conceder ou bloquear exceções por Space com motivo auditado. Desativar a API no ambiente oculta o controle e bloqueia o recurso mesmo quando existia uma liberação manual. As [regras de acesso](/guias/autenticacao) são verificadas em cada consulta. Suspensão e revogação de chaves antigas continuam disponíveis após a perda do recurso. # API pública de consulta v1 Fonte: https://docs.ruralzap.com.br/changelog/2026-10-03-api-v1 Consultas de contexto, carteiras, saldos, lançamentos, resumo e fluxo de caixa. ## O que foi disponibilizado [#o-que-foi-disponibilizado] API externa de leitura com chaves por Space, escopos, expiração, rotação e revogação. As seis consultas públicas têm contrato OpenAPI e coleção Postman. A disponibilidade depende da habilitação da API no plano ou Space. Relatórios também dependem do acesso ao recurso de fluxo de caixa. ## Comece por aqui [#comece-por-aqui] Siga a [primeira consulta](/comecar) e confira as [regras de acesso](/guias/autenticacao). Esta entrada registra a API v1, não promete escrita, webhooks ou sincronização incremental. # Documentação comum para parceiros do agro Fonte: https://docs.ruralzap.com.br/changelog/2026-10-03-documentacao-parceiros Portal RuralZap Docs e esclarecimentos sobre URL da API e contexto da chave. ## O que mudou na orientação [#o-que-mudou-na-orientação] RuralZap é o produto de gestão financeira do agro. Parceiros institucionais usam o mesmo portal de documentação em [docs.ruralzap.com.br](https://docs.ruralzap.com.br), mesmo quando operam um painel em domínio próprio. Os guias de [primeira consulta](/comecar) e [autenticação](/guias/autenticacao) distinguem o domínio do painel, o portal de documentação e a origem técnica da API. A chave já identifica reseller, Space e escopos; não é necessário um endpoint por parceiro na mesma instalação. Esta atualização é editorial. Endpoints, autenticação, escopos e formatos de resposta permanecem os mesmos; integrações existentes não precisam migrar. # Composição e recortes de lançamentos Fonte: https://docs.ruralzap.com.br/changelog/2026-10-20-composicao-consulta Valores considerados e filtros por categoria, centro e equipamento nas consultas públicas. ## Contrato adicionado [#contrato-adicionado] A listagem de lançamentos preserva `amount` como principal original e acrescenta `reportAmount`, `compositionVersion` e `compositionLines`. Os valores novos continuam como strings com quatro casas; uma compra composta ocupa um item na paginação. Lançamentos, resumo e fluxo de caixa aceitam filtros por categoria, centro de custo e equipamento. Combinações selecionam a mesma parte. Relatórios identificam a visão completa ou o recorte em `meta.mode`. ## Uso pelos integradores [#uso-pelos-integradores] Clientes atuais podem continuar lendo os campos originais. Para apresentar valores filtrados, use `reportAmount` e consulte a composição completa para auditoria. Preserve os filtros ao percorrer cursores. Os campos de liquidação do lançamento continuam descrevendo o original integral. Confira [datas e valores](/guias/dados-financeiros) e [relatórios](/receitas/relatorios). A ampliação é somente de leitura; não adiciona escrita financeira à API pública. # Changelog Fonte: https://docs.ruralzap.com.br/changelog Acompanhe a evolução da API pública. [Assinar o feed RSS](/changelog.xml) · [Ver Breaking Changes](/mudancas-incompativeis) As entradas registram mudanças disponibilizadas aos integradores. Mudanças planejadas que exigem migração indicam sua vigência e o público afetado. - 2026-10-20: [Composição e recortes de lançamentos](https://docs.ruralzap.com.br/changelog/2026-10-20-composicao-consulta.md) - 2026-10-03: [Correção da liberação da API por Space](https://docs.ruralzap.com.br/changelog/2026-10-03-api-access.md) - 2026-10-03: [API pública de consulta v1](https://docs.ruralzap.com.br/changelog/2026-10-03-api-v1.md) - 2026-10-03: [Documentação comum para parceiros do agro](https://docs.ruralzap.com.br/changelog/2026-10-03-documentacao-parceiros.md) # Sua primeira consulta Fonte: https://docs.ruralzap.com.br/comecar Prepare o acesso, confirme o Space e consulte seus primeiros saldos. ## Antes de começar [#antes-de-começar] Você precisa de acesso ao RuralZap e do recurso de API habilitado no seu plano ou Space. A documentação é pública; o acesso aos dados depende dessa habilitação. Peça ao responsável pela sua conta a liberação quando o recurso estiver indisponível. O proprietário do Space cria a integração em **Configurações → API e integrações** no [RuralZap](https://agro.ruralzap.com.br/settings/integrations/api). Escolha um nome reconhecível, prazo de validade e apenas os escopos necessários. Para esta consulta, use `balances:read`. Se sua conta é oferecida por um parceiro institucional, abra essa mesma seção no painel do parceiro. O domínio do painel pode ser diferente; a documentação é comum em [RuralZap Docs](https://docs.ruralzap.com.br). A chave é mostrada uma única vez. Guarde-a em um gerenciador de segredos. Não envie a chave a uma IA, ao suporte ou ao repositório. ## 1. Configure seu servidor [#1-configure-seu-servidor] Use Node.js 22+, Python 3 ou cURL. Configure as variáveis **no ambiente privado do servidor**: * `RURALZAP_BASE_URL=https://api.finance.meyje.com.br` * `RURALZAP_API_KEY`: valor da chave recebida, sem aspas extras. A origem não inclui `/api/v1`. O prefixo das consultas é `/api/v1/integration`. Essa origem de produção é compartilhada pelos parceiros na mesma instalação. Não troque a URL da API pelo domínio do painel nem por `docs.ruralzap.com.br`: esse é o endereço da documentação. A chave identifica automaticamente a integração, o reseller e o Space autorizados. Chaves `rzapi_test_…` e `rzapi_live_…` pertencem a ambientes distintos. Um prefixo de teste não cria um sandbox: utilize somente o ambiente fornecido pela equipe. Nossa demonstração é local, sintética e não exige chave. ## 2. Confira o contexto [#2-confira-o-contexto] ```bash curl --fail-with-body "$RURALZAP_BASE_URL/api/v1/integration/context" \ -H "Authorization: Bearer $RURALZAP_API_KEY" ``` A resposta informa `integrationId`, `spaceId`, `scopes` e `capabilities`. Confira se é o Space esperado. A chave já determina o Space: não envie `x-space-id`. ## 3. Consulte os saldos [#3-consulte-os-saldos] ```bash curl --fail-with-body "$RURALZAP_BASE_URL/api/v1/integration/balances" \ -H "Authorization: Bearer $RURALZAP_API_KEY" ``` Leia `data` para o saldo por carteira e `totals` para o total por moeda. `generatedAt` registra quando a resposta foi gerada. Valores como `"12500.0000"` são strings decimais exatas. ## Entenda o resultado [#entenda-o-resultado] Saldo corrente inclui saldo inicial, ajustes e liquidações. Não representa projeção de contas pendentes nem saldo bancário em tempo real. Carteiras arquivadas não entram na consulta. Se receber 401, confira a chave e o ambiente. Em 403, confira os escopos e o acesso atual ao recurso. Para 429, respeite o cabeçalho `Retry-After`. ## Próximo passo [#próximo-passo] Siga a [receita de saldos](/receitas/saldos), consulte a [referência de contexto](/referencia/context) ou use **Preparar prompt de integração** no início desta página. # Explore uma consulta Fonte: https://docs.ruralzap.com.br/demonstracao Entenda a resposta antes de configurar sua integração. ## Demonstração com dados sintéticos [#demonstração-com-dados-sintéticos] As carteiras, lançamentos e valores abaixo são fictícios. A interação acontece localmente no navegador, sem chave e sem chamada à API financeira. Não é um sandbox conectado a uma conta. Alterne entre saldos, páginas de lançamentos e fluxo de caixa. O JSON preserva os formatos do contrato. ## Leve para seu sistema [#leve-para-seu-sistema] Use a [primeira consulta](/comecar) para configurar acesso real ou escolha uma [receita](/receitas). Para a IA, o [contrato OpenAPI](/openapi.json) e os [exemplos](/exemplos) contêm os detalhes completos. ## Respostas sintéticas da demonstração ```json { "context": { "integrationId": "019a1000-0000-7000-8000-000000000001", "spaceId": "019a1000-0000-7000-8000-000000000001", "scopes": [ "balances:read" ], "capabilities": [ "context", "wallets", "balances" ] }, "wallets": { "data": [ { "id": "019a1000-0000-7000-8000-000000000001", "name": "Carteira sintética A", "type": "CHECKING", "currency": "BRL", "includeInNetWorth": true }, { "id": "019a1000-0000-7000-8000-000000000002", "name": "Carteira sintética B", "type": "CHECKING", "currency": "BRL", "includeInNetWorth": false }, { "id": "019a1000-0000-7000-8000-000000000003", "name": "Carteira sintética C", "type": "CHECKING", "currency": "USD", "includeInNetWorth": true } ] }, "balances": { "generatedAt": "2026-10-03T12:00:00.000Z", "data": [ { "id": "019a1000-0000-7000-8000-000000000001", "name": "Carteira sintética A", "type": "CHECKING", "currency": "BRL", "includeInNetWorth": true, "balance": "1234.5678" }, { "id": "019a1000-0000-7000-8000-000000000002", "name": "Carteira sintética B", "type": "CHECKING", "currency": "BRL", "includeInNetWorth": false, "balance": "-34.5678" }, { "id": "019a1000-0000-7000-8000-000000000003", "name": "Carteira sintética C", "type": "CHECKING", "currency": "USD", "includeInNetWorth": true, "balance": "5.0001" } ], "totals": [ { "currency": "BRL", "balance": "1200.0000" }, { "currency": "USD", "balance": "5.0001" } ] }, "transactions": { "data": [ { "id": "019a1000-0000-7000-8000-000000000001", "reference": "#105", "type": "INCOME", "status": "COMPLETED", "amount": "100.0000", "reportAmount": "1234.5678", "compositionVersion": 0, "compositionLines": [], "currency": "BRL", "description": "Venda sintética de grãos", "date": "2026-01-15", "competenceDate": null, "walletId": null, "categoryId": null, "categoryName": null, "cardId": null, "transferSourceWalletId": null, "transferDestinationWalletId": null, "isAdjustment": false, "isInvoicePayment": false, "ignored": false, "settlementManaged": false, "settledPrincipal": "100.0000", "settledCashAmount": "100.0000", "remainingAmount": "0.0000", "settlementStatus": "PAID", "createdAt": "2026-10-03T12:00:00.000Z", "updatedAt": "2026-10-03T12:00:00.000Z" }, { "id": "019a1000-0000-7000-8000-000000000002", "reference": "#105", "type": "EXPENSE", "status": "COMPLETED", "amount": "200.0000", "reportAmount": "1234.5678", "compositionVersion": 0, "compositionLines": [], "currency": "BRL", "description": "Compra sintética de insumos", "date": "2026-01-15", "competenceDate": null, "walletId": null, "categoryId": null, "categoryName": null, "cardId": null, "transferSourceWalletId": null, "transferDestinationWalletId": null, "isAdjustment": false, "isInvoicePayment": false, "ignored": false, "settlementManaged": false, "settledPrincipal": "200.0000", "settledCashAmount": "200.0000", "remainingAmount": "0.0000", "settlementStatus": "PAID", "createdAt": "2026-10-03T12:00:00.000Z", "updatedAt": "2026-10-03T12:00:00.000Z" }, { "id": "019a1000-0000-7000-8000-000000000003", "reference": "#105", "type": "INCOME", "status": "COMPLETED", "amount": "300.0000", "reportAmount": "1234.5678", "compositionVersion": 0, "compositionLines": [], "currency": "BRL", "description": "Serviço sintético", "date": "2026-01-15", "competenceDate": null, "walletId": null, "categoryId": null, "categoryName": null, "cardId": null, "transferSourceWalletId": null, "transferDestinationWalletId": null, "isAdjustment": false, "isInvoicePayment": false, "ignored": false, "settlementManaged": false, "settledPrincipal": "300.0000", "settledCashAmount": "300.0000", "remainingAmount": "0.0000", "settlementStatus": "PAID", "createdAt": "2026-10-03T12:00:00.000Z", "updatedAt": "2026-10-03T12:00:00.000Z" } ], "meta": { "hasMore": false, "nextCursor": null } }, "reports-summary": { "meta": { "generatedAt": "2026-10-03T12:00:00.000Z", "startDate": "2026-01-01", "endDate": "2026-01-31", "timezone": "America/Sao_Paulo", "walletId": null, "categoryId": null, "costCenterId": null, "assetId": null, "mode": "cash", "groupBy": "month" }, "currency": "BRL", "summary": { "openingBalance": "1000.0000", "totalInflows": "600.0000", "totalOutflows": "400.0000", "netCashflow": "200.0000", "totalAdjustments": "0.0000", "closingBalance": "1200.0000" } }, "reports-cashflow": { "meta": { "generatedAt": "2026-10-03T12:00:00.000Z", "startDate": "2026-01-01", "endDate": "2026-01-31", "timezone": "America/Sao_Paulo", "walletId": null, "categoryId": null, "costCenterId": null, "assetId": null, "mode": "cash", "groupBy": "month" }, "currency": "BRL", "summary": { "openingBalance": "1000.0000", "totalInflows": "600.0000", "totalOutflows": "400.0000", "netCashflow": "200.0000", "totalAdjustments": "0.0000", "closingBalance": "1200.0000" }, "data": [ { "period": "2026-01", "inflows": "600.0000", "outflows": "400.0000", "netFlow": "200.0000", "adjustments": "0.0000", "runningBalance": "1200.0000" } ] } } ``` # Exemplos executáveis Fonte: https://docs.ruralzap.com.br/exemplos Código de consulta e downloads gerados do mesmo contrato da referência. Configure RURALZAP_BASE_URL e RURALZAP_API_KEY no servidor. Nunca cole chaves em prompts ou código público. Exemplos de chamada única não implementam paginação ou retentativas; use os leitores completos abaixo para percorrer lançamentos. [OpenAPI](/openapi.json) · [Postman](/postman.json) * Consultar contexto da integração: [cURL](/examples/context.sh), [TypeScript](/examples/context.ts), [Python](/examples/context.py). * Listar carteiras ativas: [cURL](/examples/wallets.sh), [TypeScript](/examples/wallets.ts), [Python](/examples/wallets.py). * Consultar saldos correntes: [cURL](/examples/balances.sh), [TypeScript](/examples/balances.ts), [Python](/examples/balances.py). * Consultar lançamentos por período: [cURL](/examples/transactions.sh), [TypeScript](/examples/transactions.ts), [Python](/examples/transactions.py). * Consultar resumo financeiro realizado: [cURL](/examples/reports-summary.sh), [TypeScript](/examples/reports-summary.ts), [Python](/examples/reports-summary.py). * Consultar fluxo de caixa realizado: [cURL](/examples/reports-cashflow.sh), [TypeScript](/examples/reports-cashflow.ts), [Python](/examples/reports-cashflow.py). ## Leitor completo em TypeScript [#leitor-completo-em-typescript] [Baixar read-transactions.ts](/examples/read-transactions.ts) ```typescript /** * RuralZap — exemplo executável no servidor com Node.js 22+ e tsx. * npx --yes tsx read-transactions.ts 2026-01-01 2026-01-31 * Configure RURALZAP_BASE_URL (origem) e RURALZAP_API_KEY no ambiente privado. * Não execute este arquivo no navegador nem registre respostas financeiras. */ import process from "node:process"; import { setTimeout as sleep } from "node:timers/promises"; const MAX_ATTEMPTS = 4; const MAX_PAGES = 10_000; const TIMEOUT_MS = 30_000; const MONEY = /^-?\d+\.\d{4}$/; class IntegrationError extends Error {} type Transaction = { id: string; amount: string; currency: string; date: string; }; type TransactionPage = { data: Transaction[]; meta: { hasMore: boolean; nextCursor: string | null }; }; function isObject(value: unknown): value is Record { return typeof value === "object" && value !== null && !Array.isArray(value); } function dateOnlyMilliseconds(value: string): number { if (!/^\d{4}-\d{2}-\d{2}$/.test(value)) { throw new IntegrationError("Use datas no formato YYYY-MM-DD."); } const [year, month, day] = value.split("-").map(Number); const leap = year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0); const days = [31, leap ? 29 : 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]; if ( year < 100 || month < 1 || month > 12 || day < 1 || day > days[month - 1] ) { throw new IntegrationError("Data de calendário inválida."); } // Somente para comparar o intervalo. Enviamos as strings originais sem fuso. return Date.UTC(year, month - 1, day); } function configuration() { const base = process.env.RURALZAP_BASE_URL; const key = process.env.RURALZAP_API_KEY; if (!base || !key) { throw new IntegrationError( "Configure RURALZAP_BASE_URL e RURALZAP_API_KEY.", ); } let origin: URL; try { origin = new URL(base); } catch { throw new IntegrationError("RURALZAP_BASE_URL deve ser uma origem válida."); } const local = ["localhost", "127.0.0.1", "[::1]"].includes(origin.hostname); if ( (origin.protocol !== "https:" && !(local && origin.protocol === "http:")) || origin.username || origin.password || origin.search || origin.hash || origin.pathname !== "/" ) { throw new IntegrationError( "Use uma origem HTTPS sem caminho, credenciais ou query. HTTP só é aceito em localhost.", ); } const [startDate, endDate] = process.argv.slice(2); if (!startDate || !endDate || process.argv.length !== 4) { throw new IntegrationError( "Uso: tsx read-transactions.ts YYYY-MM-DD YYYY-MM-DD", ); } const days = (dateOnlyMilliseconds(endDate) - dateOnlyMilliseconds(startDate)) / 86_400_000 + 1; if (days < 1 || days > 366) { throw new IntegrationError( "O período deve ser ordenado e ter até 366 dias inclusivos.", ); } return { origin, key, startDate, endDate }; } function parsePage(value: unknown): TransactionPage { if (!isObject(value) || !Array.isArray(value.data) || !isObject(value.meta)) { throw new IntegrationError( "Resposta incompatível com o contrato de paginação.", ); } const { hasMore, nextCursor } = value.meta; if ( typeof hasMore !== "boolean" || (nextCursor !== null && typeof nextCursor !== "string") || (hasMore && (typeof nextCursor !== "string" || nextCursor.length === 0)) ) { throw new IntegrationError("Metadados de paginação inválidos."); } const rows: unknown[] = value.data; const data = rows.map((row): Transaction => { if ( !isObject(row) || typeof row.id !== "string" || row.id.length === 0 || typeof row.amount !== "string" || !MONEY.test(row.amount) || typeof row.currency !== "string" || !/^[A-Z]{3}$/.test(row.currency) || typeof row.date !== "string" ) { throw new IntegrationError( "Lançamento incompatível com o contrato esperado.", ); } dateOnlyMilliseconds(row.date); // Campos adicionais são ignorados para aceitar evoluções compatíveis da v1. return { id: row.id, amount: row.amount, currency: row.currency, date: row.date, }; }); return { data, meta: { hasMore, nextCursor } }; } function retryDelayMs(response: Response, attempt: number): number { const retryAfter = response.headers.get("retry-after"); const seconds = retryAfter !== null && /^\d+$/.test(retryAfter) ? Number(retryAfter) : null; const delay = seconds === null ? response.status === 429 ? 60_000 : 1_000 * 2 ** attempt : seconds * 1_000; if (!Number.isFinite(delay) || delay > 120_000) { throw new IntegrationError( "Servidor pediu espera longa. Reexecute depois do prazo de Retry-After.", ); } return delay + Math.floor(Math.random() * 250); } async function fetchPage(url: URL, key: string): Promise { for (let attempt = 0; attempt < MAX_ATTEMPTS; attempt += 1) { let response: Response; try { response = await fetch(url, { headers: { Authorization: `Bearer ${key}`, Accept: "application/json" }, signal: AbortSignal.timeout(TIMEOUT_MS), redirect: "error", // Nunca encaminhar uma chave por redirecionamento. }); } catch { if (attempt === MAX_ATTEMPTS - 1) { throw new IntegrationError( "Falha de conexão ou timeout após tentativas limitadas.", ); } await sleep(1_000 * 2 ** attempt + Math.floor(Math.random() * 250)); continue; } if (response.ok) { const payload: unknown = await response.json(); return parsePage(payload); } const requestId = response.headers.get("x-request-id"); const safeId = requestId && /^[a-f0-9-]{36}$/i.test(requestId) ? `; requestId=${requestId}` : ""; // Não ler nem registrar o corpo financeiro ou headers de autenticação. await response.body?.cancel(); if ( (response.status === 429 || response.status === 503) && attempt < MAX_ATTEMPTS - 1 ) { await sleep(retryDelayMs(response, attempt)); continue; } throw new IntegrationError( `HTTP ${response.status}${safeId}. Confira o guia de erros; a execução foi encerrada.`, ); } throw new IntegrationError("Limite de tentativas atingido."); } async function main(): Promise { const { origin, key, startDate, endDate } = configuration(); const url = new URL("/api/v1/integration/transactions", origin); url.searchParams.set("startDate", startDate); url.searchParams.set("endDate", endDate); url.searchParams.set("limit", "100"); const cursors = new Set(); let count = 0; for (let pageNumber = 1; pageNumber <= MAX_PAGES; pageNumber += 1) { const page = await fetchPage(url, key); for (const transaction of page.data) { // Integração real: faça upsert pelo transaction.id no seu armazenamento. // Preserve transaction.amount como string/DECIMAL(…,4), nunca Number/parseFloat. // Os campos são validados; este exemplo não grava nem imprime dados financeiros. void transaction; count += 1; } if (!page.meta.hasMore) { console.log( `Consulta concluída: ${count} lançamentos recebidos em ${pageNumber} página(s).`, ); return; } const cursor = page.meta.nextCursor; if (!cursor || cursors.has(cursor)) { throw new IntegrationError( "Cursor ausente ou repetido; consulta interrompida.", ); } cursors.add(cursor); url.searchParams.set("cursor", cursor); } throw new IntegrationError( "Limite local de páginas atingido. Divida a consulta em períodos menores.", ); } // Releia o período para conciliar alterações/exclusões por id: não é feed incremental // nem snapshot. Não derive receita ou saldo somando lançamentos; use os relatórios. void main().catch((error: unknown) => { console.error( error instanceof IntegrationError ? error.message : "Falha local ao processar a resposta. Nenhum payload foi registrado.", ); process.exitCode = 1; }); ``` ## Leitor completo em Python [#leitor-completo-em-python] [Baixar read-transactions.py](/examples/read-transactions.py) ```python """RuralZap: Python 3.10+, somente biblioteca padrão, execução no servidor. python read-transactions.py 2026-01-01 2026-01-31 Configure RURALZAP_BASE_URL e RURALZAP_API_KEY no ambiente privado. O exemplo valida dados e imprime somente a contagem; não persiste lançamentos. """ import json import os import random import re import sys import time from datetime import date from decimal import Decimal from urllib.error import HTTPError, URLError from urllib.parse import urlencode, urlsplit from urllib.request import HTTPRedirectHandler, Request, build_opener MAX_ATTEMPTS = 4 MAX_PAGES = 10_000 TIMEOUT_SECONDS = 30 MONEY = re.compile(r"^-?\d+\.\d{4}$") class IntegrationError(Exception): """Mensagens controladas, sem credenciais ou respostas financeiras.""" class NoRedirects(HTTPRedirectHandler): def redirect_request(self, request, response, code, message, headers, new_url): # Não encaminhar a chave para uma origem indicada por redirecionamento. return None def configuration(): origin = os.environ.get("RURALZAP_BASE_URL", "") key = os.environ.get("RURALZAP_API_KEY", "") if not origin or not key: raise IntegrationError("Configure RURALZAP_BASE_URL e RURALZAP_API_KEY.") try: parsed = urlsplit(origin) local = parsed.hostname in {"localhost", "127.0.0.1", "::1"} valid_transport = parsed.scheme == "https" or (local and parsed.scheme == "http") valid_origin = parsed.hostname and not ( parsed.username or parsed.password or parsed.query or parsed.fragment or parsed.path not in {"", "/"} ) except ValueError: raise IntegrationError("RURALZAP_BASE_URL deve ser uma origem válida.") from None if not valid_transport or not valid_origin: raise IntegrationError("Use uma origem HTTPS sem caminho, credenciais ou query. HTTP só é aceito em localhost.") if len(sys.argv) != 3: raise IntegrationError("Uso: python read-transactions.py YYYY-MM-DD YYYY-MM-DD") start_date, end_date = sys.argv[1:] try: if not all(re.fullmatch(r"\d{4}-\d{2}-\d{2}", value) for value in (start_date, end_date)): raise ValueError() days = (date.fromisoformat(end_date) - date.fromisoformat(start_date)).days + 1 except ValueError: raise IntegrationError("Use datas válidas no formato YYYY-MM-DD.") from None if not 1 <= days <= 366: raise IntegrationError("O período deve ser ordenado e ter até 366 dias inclusivos.") return origin.rstrip("/"), key, start_date, end_date def parse_page(value): if not isinstance(value, dict) or not isinstance(value.get("data"), list) or not isinstance(value.get("meta"), dict): raise IntegrationError("Resposta incompatível com o contrato de paginação.") has_more = value["meta"].get("hasMore") next_cursor = value["meta"].get("nextCursor") if type(has_more) is not bool or (next_cursor is not None and not isinstance(next_cursor, str)) or (has_more and not next_cursor): raise IntegrationError("Metadados de paginação inválidos.") rows = [] for row in value["data"]: if not isinstance(row, dict): raise IntegrationError("Lançamento inválido.") identifier, amount, currency, financial_date = (row.get(field) for field in ("id", "amount", "currency", "date")) if not ( isinstance(identifier, str) and identifier and isinstance(amount, str) and MONEY.fullmatch(amount) and isinstance(currency, str) and re.fullmatch(r"[A-Z]{3}", currency) and isinstance(financial_date, str) and re.fullmatch(r"\d{4}-\d{2}-\d{2}", financial_date) ): raise IntegrationError("Lançamento incompatível com o contrato esperado.") try: date.fromisoformat(financial_date) except ValueError: raise IntegrationError("Data financeira inválida na resposta.") from None # Decimal recebe a string original: nunca passar por float. rows.append({"id": identifier, "amount": Decimal(amount), "currency": currency, "date": financial_date}) return rows, has_more, next_cursor def retry_delay(error, attempt): raw = error.headers.get("Retry-After") if raw is not None and re.fullmatch(r"\d+", raw): delay = int(raw) else: delay = 60 if error.code == 429 else 2 ** attempt if delay > 120: raise IntegrationError("Servidor pediu espera longa. Reexecute depois do prazo de Retry-After.") return delay + random.uniform(0, 0.25) def fetch_page(opener, url, key): for attempt in range(MAX_ATTEMPTS): request = Request(url, headers={"Authorization": f"Bearer {key}", "Accept": "application/json"}, method="GET") try: with opener.open(request, timeout=TIMEOUT_SECONDS) as response: return parse_page(json.load(response)) except HTTPError as error: # Nunca ler ou registrar body, URL ou headers que contenham credenciais. request_id = error.headers.get("X-Request-Id", "") safe_id = f"; requestId={request_id}" if re.fullmatch(r"[a-fA-F0-9-]{36}", request_id) else "" error.close() if error.code in {429, 503} and attempt < MAX_ATTEMPTS - 1: time.sleep(retry_delay(error, attempt)) continue raise IntegrationError(f"HTTP {error.code}{safe_id}. Confira o guia de erros; a execução foi encerrada.") from None except (URLError, TimeoutError): if attempt == MAX_ATTEMPTS - 1: raise IntegrationError("Falha de conexão ou timeout após tentativas limitadas.") from None time.sleep(2 ** attempt + random.uniform(0, 0.25)) raise IntegrationError("Limite de tentativas atingido.") def main(): origin, key, start_date, end_date = configuration() parameters = {"startDate": start_date, "endDate": end_date, "limit": "100"} opener = build_opener(NoRedirects()) cursors = set() count = 0 for page_number in range(1, MAX_PAGES + 1): url = f"{origin}/api/v1/integration/transactions?{urlencode(parameters)}" rows, has_more, next_cursor = fetch_page(opener, url, key) for transaction in rows: # Integração real: upsert pelo transaction["id"] no seu armazenamento. # Para salvar amount: coluna DECIMAL(…,4) ou format(transaction["amount"], ".4f"). # Este exemplo não grava nem imprime dados financeiros. count += 1 if not has_more: print(f"Consulta concluída: {count} lançamentos recebidos em {page_number} página(s).") return if not next_cursor or next_cursor in cursors: raise IntegrationError("Cursor ausente ou repetido; consulta interrompida.") cursors.add(next_cursor) parameters["cursor"] = next_cursor raise IntegrationError("Limite local de páginas atingido. Divida a consulta em períodos menores.") if __name__ == "__main__": try: # Releia o período para conciliar alterações/exclusões por id; não é feed # incremental nem snapshot. Para receitas/saldos, use os relatórios canônicos. main() except IntegrationError as error: print(str(error), file=sys.stderr) sys.exit(1) except Exception: print("Falha local ao processar a resposta. Nenhum payload foi registrado.", file=sys.stderr) sys.exit(1) ``` # Autenticação e permissões Fonte: https://docs.ruralzap.com.br/guias/autenticacao Uma chave representa uma integração de um único Space. ## Envie a chave no cabeçalho [#envie-a-chave-no-cabeçalho] `Authorization: Bearer RURALZAP_API_KEY` Use uma chave de integração criada pelo proprietário do Space em [API e integrações](https://agro.ruralzap.com.br/settings/integrations/api). JWT da sessão e credenciais MCP não autenticam esta API. Em contas de parceiros institucionais, a chave é criada nessa seção do painel do parceiro. A documentação e o contrato da API são os mesmos. ## Space e escopos [#space-e-escopos] O Space isola os dados financeiros. A chave identifica automaticamente a integração, o reseller, o Space e os escopos autorizados. A API não usa o domínio do painel para escolher esses dados. Para outro Space, obtenha outra integração autorizada. Não envie `x-space-id`, `x-reseller-id`, `x-user-id` ou `x-api-key`, nem identificadores de tenant ou credenciais na query: a API rejeita essas tentativas com 400 `INVALID_REQUEST`. Autentique somente por `Authorization: Bearer`. | Consulta | Escopo | | ----------------------- | ------------------------------------------ | | Contexto | Chave válida e acesso à API | | Carteiras e saldos | `balances:read` | | Lançamentos | `transactions:read` | | Resumo e fluxo de caixa | `reports:read` e recurso de fluxo de caixa | A habilitação da API e os direitos do plano são conferidos em cada chamada. Ter um escopo na chave não substitui o acesso ao recurso. Use [contexto](/referencia/context) para descobrir as capacidades atuais. O card **API e integrações** nas Configurações aparece somente com a API habilitada para o ambiente e incluída no plano contratado, ou com a API habilitada para o ambiente e uma liberação manual vigente para esse Space. Habilitar a API no ambiente sem incluí-la no plano não concede acesso automaticamente. Solicite a liberação à equipe responsável pelo seu ambiente. Após perder o acesso, a gestão pelo link direto continua permitindo suspender integrações e revogar chaves antigas. ## Ambientes [#ambientes] Chaves de teste e produção não são intercambiáveis. A origem de produção é `https://api.finance.meyje.com.br`. Para testes com API real, utilize exclusivamente o ambiente disponibilizado para sua conta. Não há cadastro de sandbox público neste portal. Na mesma instalação, essa origem é comum a RuralZap e seus parceiros. Um domínio ou subdomínio próprio do painel não exige outra URL de integração. O portal `https://docs.ruralzap.com.br` serve a documentação, não as consultas de dados. ## Rotação e revogação [#rotação-e-revogação] Faça a rotação na gestão da integração, atualize o segredo no seu servidor e confira o contexto novamente. Respeite o prazo de sobreposição informado pelo produto; não presuma validade indefinida da chave anterior. Se houver exposição, revogue a chave. Não inclua credenciais em URLs, logs, exemplos, prompts ou chamados de suporte. Revogação, expiração, perda de acesso do responsável e alteração de direitos podem interromper consultas. # Datas e valores monetários Fonte: https://docs.ruralzap.com.br/guias/dados-financeiros Preserve a precisão e o significado financeiro das respostas. ## Dinheiro [#dinheiro] Valores monetários são strings com quatro casas decimais: `"1234.5678"`. Preserve esse formato no transporte e armazenamento. Use biblioteca decimal ou inteiros escalados para calcular; não use float, `parseFloat` ou `Number` para somar dinheiro. Moedas diferentes não são somadas. Saldos vêm agrupados por moeda; relatórios desta versão suportam BRL. ## Datas financeiras [#datas-financeiras] `startDate`, `endDate` e datas de negócio usam `YYYY-MM-DD`, sem horário. O intervalo inclui os dois extremos e tem no máximo 366 dias. Não converta essas datas para UTC ou para o fuso do navegador. `createdAt`, `updatedAt` e `generatedAt` são instantes com horário. Não os confunda com competência ou data financeira. Relatórios informam o contexto de negócio `America/Sao_Paulo`. ## Saldo não é projeção [#saldo-não-é-projeção] Saldos incluem abertura, ajustes e liquidações e excluem pendências e compras de cartão não pagas. Fluxo de caixa e resumo são realizados, não projeções de valores futuros. ## Lançamentos não são um relatório somável [#lançamentos-não-são-um-relatório-somável] A listagem inclui pendentes, cancelados, ajustes, transferências e pagamentos de fatura, com indicadores explícitos. Use `id` como identificador estável. Observe `ignored`, `isAdjustment`, `isInvoicePayment` e os campos de liquidação. Para indicadores, use os [relatórios oficiais](/receitas/relatorios). Somar todos os lançamentos pode duplicar transferências ou pagamentos de fatura e produzir indicadores incorretos. ## Composição e recortes gerenciais [#composição-e-recortes-gerenciais] Uma compra continua sendo um lançamento, mesmo quando dividida em categorias, centros e equipamentos. `amount` é o principal original integral; `reportAmount` é o principal considerado pelas partes que atendem aos filtros. Ambos são strings com quatro casas. Os campos de liquidação do lançamento continuam descrevendo o original integral. `compositionVersion` igual a zero identifica a classificação legada. Uma versão positiva usa exclusivamente `compositionLines`, com valores exatos e referências legíveis. A resposta contém a composição completa para auditoria, inclusive as partes que não entraram no recorte. Categoria ausente no cabeçalho pode significar categorias diferentes entre as partes; não escolha a primeira como categoria da compra. `categoryId`, `costCenterId` e `assetId` precisam corresponder à mesma parte. `costCenterId` aceita UUIDs separados por vírgula ou `UNCLASSIFIED`: nas composições, este último considera somente partes sem centro; no legado, lançamentos sem rateio. Equipamentos arquivados continuam identificáveis no histórico autorizado. Nos relatórios, `meta.mode` informa `cash` para a visão completa ou `slice` para um recorte gerencial. O caixa usa a data e os componentes da baixa: principal, acréscimos e desconto são distribuídos separadamente, com precisão de quatro casas. Abertura e fechamento de um recorte não representam o saldo bancário integral da carteira. Estornos retiram a atribuição da baixa original; reclassificações atualizam a leitura gerencial corrente preservando a auditoria. A API permanece somente leitura. Esses campos não habilitam criação, reclassificação ou baixa por API pública. # Erros e limites Fonte: https://docs.ruralzap.com.br/guias/erros Saiba quando corrigir a requisição, rever acesso ou tentar novamente. ## Causa e solução [#causa-e-solução] | HTTP | Causa provável | Próxima ação | | ---- | ------------------------------------------------------- | -------------------------------------------------------- | | 400 | Data, intervalo, cursor ou filtro inválido | Corrija conforme o contrato. Não repita a mesma entrada. | | 401 | Chave inválida, expirada, revogada ou de outro ambiente | Confira o segredo e a origem no servidor. | | 403 | Escopo ou direito ao recurso indisponível | Revise permissões, habilitação e acesso do responsável. | | 404 | Recurso ou filtro fora do Space | Confira o identificador e o Space da integração. | | 429 | Limite de chamadas excedido | Aguarde os segundos de Retry-After. | | 503 | Serviço temporariamente indisponível | Faça tentativas limitadas com espera progressiva. | Erros da API pública usam `error.code`, `error.message` e `error.requestId`. Proxies podem retornar outro formato; valide o tipo da resposta antes de interpretar JSON. ## Limites por minuto [#limites-por-minuto] | Categoria | Integração | Space | | ---------------- | ---------- | ----- | | Consultas gerais | 60 | 120 | | Relatórios | 10 | 20 | Chamadas também passam pela proteção geral da API. `Retry-After` é a orientação operacional no 429; não calcule um prazo assumindo que somente uma camada limita o tráfego. Evite disparos concorrentes desnecessários. Use timeout, espera progressiva e um teto de tentativas. Não repita automaticamente erros de autenticação ou validação. ## Diagnóstico seguro [#diagnóstico-seguro] Registre status HTTP, rota e identificador de requisição. Não registre chaves ou respostas financeiras. Envie o identificador pelo suporte disponível no produto. Respostas financeiras usam `Cache-Control: no-store`. Armazenamento no seu sistema precisa respeitar as permissões e a política de dados da sua organização. # Guias de integração Fonte: https://docs.ruralzap.com.br/guias Entenda o contrato antes de conectar os dados da sua operação. * [Autenticação e permissões](/guias/autenticacao): chave, Space, planos e rotação. * [Datas e valores monetários](/guias/dados-financeiros): significado dos dados e precisão. * [Paginação](/guias/paginacao): percorra lançamentos sem perder o contexto. * [Erros e limites](/guias/erros): identifique a causa e a próxima ação. * [Integrar com IA](/integrar-com-ia): entregue fontes e instruções ao seu agente. A API v1 permite consultas. Escrita, webhooks de sincronização e SDK oficial não fazem parte desta versão. # Paginação de lançamentos Fonte: https://docs.ruralzap.com.br/guias/paginacao Percorra páginas mantendo os filtros e tratando os limites do contrato. ## Uma consulta, várias páginas [#uma-consulta-várias-páginas] Informe `startDate` e `endDate`. O limite padrão é 50 e o máximo é 100. Os resultados vêm em ordem crescente de `createdAt,id`. 1. Faça a primeira chamada sem cursor. 2. Processe `data`, usando `id` como chave no sistema de destino. 3. Enquanto `meta.hasMore` for verdadeiro, envie `meta.nextCursor` no parâmetro `cursor`. 4. Mantenha período, filtros e limite idênticos, incluindo `categoryId`, `costCenterId` e `assetId` quando informados. 5. Encerre quando `hasMore` for falso. O cursor vale por 24 horas. Não decodifique nem construa seu próprio cursor. Se expirar, reinicie a consulta e trate duplicatas por ID no destino. ## Limites importantes [#limites-importantes] Paginação não representa snapshot. Mudanças e exclusões durante a travessia podem alterar os resultados. Itens apagados são excluídos da listagem; a API não entrega tombstones nem um feed incremental. Para atualizar um sistema externo, planeje releituras periódicas e reconciliação do intervalo necessário. Não prometa sincronização completa de exclusões usando apenas `updatedAt`. Use os [exemplos completos em TypeScript e Python](/exemplos), que limitam tentativas, detectam cursor repetido e preservam filtros. # Integre com a IA que você já usa Fonte: https://docs.ruralzap.com.br/integrar-com-ia Entregue contexto confiável ao seu agente, com contrato e exemplos atualizados. ## Prepare o contexto [#prepare-o-contexto] Use **Preparar prompt de integração** no fim de qualquer página. Escolha TypeScript, Python, cURL ou n8n e descreva a tarefa. Copie o texto para seu agente de desenvolvimento. O prompt indica fontes oficiais, variáveis de ambiente e regras de dinheiro, datas, paginação e erros. Não inclua a chave: configure-a no ambiente privado onde a integração será executada. ## Fontes legíveis por máquina [#fontes-legíveis-por-máquina] * [Índice llms.txt](/llms.txt) * [Documentação completa](/llms-full.txt) * [Contrato OpenAPI](/openapi.json) * [Coleção Postman](/postman.json) * [Exemplos executáveis](/exemplos) Acrescente `.md` à URL de uma página para obter o Markdown. [Exemplo: autenticação](/guias/autenticacao.md). O índice inicial está em [/index.md](/index.md). ## O que pedir à IA [#o-que-pedir-à-ia] Peça código executável, instruções de configuração e testes com dados sintéticos. Exija fontes para rotas e campos. Valide permissões e a interpretação financeira antes de conectar dados reais. `llms.txt` facilita descoberta; não garante que todos os modelos leiam automaticamente o site. Forneça as URLs explicitamente. ## Assistente do portal [#assistente-do-portal] Nesta versão, a busca encontra conteúdo e os prompts levam esse contexto à sua IA. Um assistente de perguntas e respostas dentro do portal está previsto para uma etapa posterior, sem data prometida. # Breaking Changes Fonte: https://docs.ruralzap.com.br/mudancas-incompativeis Saiba quando uma alteração exige ação na sua integração. ## Situação atual [#situação-atual] Os avisos publicados aparecem nesta página e no changelog. Quando a lista estiver vazia, não há mudança incompatível anunciada nesta publicação. ## Como acompanhar [#como-acompanhar] As mudanças que exigirem ação serão publicadas com versão afetada, público impactado, data de vigência, exemplos antes/depois e passos de migração. Avisos também aparecerão nas páginas afetadas. Consulte o [changelog](/changelog) ou assine o [feed RSS](/changelog.xml). Não há serviço de assinatura de e-mail neste portal. ## Compatibilidade [#compatibilidade] Implemente leitura tolerante a campos adicionais. Respeite os tipos e não dependa da ordem de propriedades JSON. Mudanças em campos obrigatórios, tipos e comportamentos exigem avaliação de compatibilidade. A documentação não estabelece um prazo universal de descontinuação. Cada aviso terá as condições concretas da alteração; nenhuma migração deve depender de um prazo presumido. Nenhuma mudança incompatível anunciada nesta publicação. # Receitas de integração Fonte: https://docs.ruralzap.com.br/receitas Resolva uma tarefa inteira, do acesso ao resultado esperado. | Quero… | Receita | | ---------------------------------------------- | ----------------------------------------------- | | Mostrar a posição das carteiras no meu sistema | [Painel de saldos](/receitas/saldos) | | Ler lançamentos de um período | [Percorrer lançamentos](/receitas/lancamentos) | | Acompanhar o financeiro realizado | [Resumo e fluxo de caixa](/receitas/relatorios) | | Automatizar consultas sem criar um aplicativo | [Consultar pelo n8n](/receitas/n8n) | Cada receita conecta pré-requisitos, passos, código, verificação e tratamento de falhas. Comece pela demonstração se ainda não tiver uma chave. # Percorra lançamentos por período Fonte: https://docs.ruralzap.com.br/receitas/lancamentos Alimente seu sistema com páginas de lançamentos e IDs estáveis. ## Objetivo e pré-requisitos [#objetivo-e-pré-requisitos] Ler lançamentos de um intervalo com `transactions:read`. Configure chave e origem no servidor. Use um período inclusivo de até 366 dias. ## 1. Execute o exemplo completo [#1-execute-o-exemplo-completo] Baixe [TypeScript](/examples/read-transactions.ts) ou [Python](/examples/read-transactions.py). Os arquivos exibidos em [Exemplos](/exemplos) são os mesmos disponíveis para download. ```bash npx tsx read-transactions.ts 2026-01-01 2026-01-31 # Ou, com Python 3: python read-transactions.py 2026-01-01 2026-01-31 ``` ## 2. Percorra mantendo o contexto [#2-percorra-mantendo-o-contexto] O exemplo faz a requisição inicial, valida a resposta, trata tentativas e acompanha `meta.nextCursor`. Adapte o ponto de processamento dos itens para seu destino, usando `id` como identificador estável. ## 3. Valide o resultado [#3-valide-o-resultado] Verifique término por `hasMore: false`, ausência de cursor repetido e manutenção de filtros. Preserve valores como strings. Não registre payloads financeiros para depurar. ## Compras compostas [#compras-compostas] Para consultar um equipamento, acrescente `assetId` com seu UUID. Categoria e centro podem ser combinados na mesma consulta. Mantenha todos os filtros também nas páginas seguintes; a composição não multiplica a compra na paginação. Use `reportAmount` para apresentar o principal selecionado e mantenha `amount` como original auditável. Não some `compositionLines` novamente sobre `reportAmount`: a composição completa já explica o lançamento. Para caixa efetivamente pago, consulte os relatórios com os mesmos filtros. ## Erros comuns e limites [#erros-comuns-e-limites] Cursor expirado exige reiniciar a consulta. Se o processo parar, evite duplicatas por ID ao repetir. A API exclui apagados e não garante snapshot ou feed incremental: [entenda as limitações](/guias/paginacao). ## Próximos passos [#próximos-passos] Para indicadores, utilize a [receita de relatórios](/receitas/relatorios); não some indiscriminadamente os lançamentos retornados. # Consulte pelo n8n Fonte: https://docs.ruralzap.com.br/receitas/n8n Configure uma chamada HTTP mantendo a credencial fora do workflow exportado. ## Objetivo e pré-requisitos [#objetivo-e-pré-requisitos] Criar um workflow de consulta de saldos. Você precisa de uma instância n8n e de uma integração com `balances:read`. ## 1. Cadastre a credencial [#1-cadastre-a-credencial] Crie uma credencial de autenticação por cabeçalho no n8n, com nome `Authorization` e valor `Bearer SUA_CHAVE`. Insira o segredo diretamente no gerenciador de credenciais, nunca em um campo comum do workflow. ## 2. Configure o HTTP Request [#2-configure-o-http-request] * Método: GET. * URL: `https://api.finance.meyje.com.br/api/v1/integration/context`. * Autenticação: selecione a credencial cadastrada. * Resposta: JSON. Execute uma vez e confira o Space e as capacidades. Depois troque o caminho final para `balances`. ## 3. Trate resultado e falhas [#3-trate-resultado-e-falhas] Leia `data` e `totals`. Preserve valores como strings; não converta dinheiro com operações numéricas de ponto flutuante. Configure timeout e tentativas limitadas. Em 429, respeite `Retry-After`; não repita cegamente falhas de acesso. ## Resultado esperado [#resultado-esperado] Uma saída JSON com carteiras, totais por moeda e instante de geração. Proteja o histórico de execuções do n8n, pois ele pode armazenar respostas financeiras. ## Erros comuns [#erros-comuns] Chave cadastrada sem o prefixo Bearer retorna falha de autenticação. Credencial válida sem acesso ao recurso não resolve um 403. Não exporte o segredo junto ao workflow. ## Próximos passos [#próximos-passos] Para lançamentos, configure a [paginação por cursor](/guias/paginacao), preservando filtros e verificando o término. Para relatórios, use a [receita específica](/receitas/relatorios). # Consulte resumo e fluxo de caixa Fonte: https://docs.ruralzap.com.br/receitas/relatorios Use os cálculos oficiais do financeiro realizado no seu sistema. ## Objetivo e pré-requisitos [#objetivo-e-pré-requisitos] Consultar o resumo e a evolução do caixa com `reports:read` e acesso ao recurso de fluxo de caixa. Configure as [variáveis no servidor](/comecar). ## 1. Defina o período [#1-defina-o-período] Informe datas financeiras inclusivas. Por exemplo, janeiro de 2026: ```bash curl --fail-with-body \ "$RURALZAP_BASE_URL/api/v1/integration/reports/summary?startDate=2026-01-01&endDate=2026-01-31" \ -H "Authorization: Bearer $RURALZAP_API_KEY" ``` ## 2. Consulte a série [#2-consulte-a-série] ```bash curl --fail-with-body \ "$RURALZAP_BASE_URL/api/v1/integration/reports/cashflow?startDate=2026-01-01&endDate=2026-01-31&groupBy=day" \ -H "Authorization: Bearer $RURALZAP_API_KEY" ``` Também estão disponíveis [Python para resumo](/examples/reports-summary.py) e [Python para fluxo de caixa](/examples/reports-cashflow.py). ## 3. Interprete os campos [#3-interprete-os-campos] `summary` informa abertura, entradas, saídas, resultado, ajustes e fechamento. `data` no fluxo traz os períodos. `meta` informa o intervalo e a carteira selecionada. Confira `currency` antes de apresentar valores. O relatório é realizado e suporta BRL. Períodos sem movimento podem estar ausentes. Selecionar `walletId` inclui transferências externas dessa carteira conforme o cálculo oficial. ## Recorte por classificação [#recorte-por-classificação] Resumo e série aceitam `categoryId`, `costCenterId` e `assetId`, sempre sobre a mesma parte da composição. Por exemplo, acrescente `&assetId=019a1000-0000-7000-8000-000000000001` à URL e preserve os demais filtros. O identificador é sintético: use um equipamento do Space autorizado pela chave. Confira `meta.mode`: `slice` identifica um recorte gerencial. Uma consulta por categoria ou equipamento começa o resultado do período em zero e não apresenta o saldo bancário integral. Um recorte por centro pode incluir o saldo analítico de abertura correspondente. Não compare esse fechamento com `/balances` como se fossem a mesma medida. ## Resultado esperado e erros comuns [#resultado-esperado-e-erros-comuns] O resultado segue o relatório do produto com os mesmos filtros. 403 pode indicar ausência do recurso mesmo que a chave tenha o escopo; 400 pode indicar intervalo inválido. Respeite os limites específicos de relatórios. ## Próximos passos [#próximos-passos] Compare a apresentação com a [demonstração](/demonstracao) e confira [resumo](/referencia/reports-summary) e [fluxo de caixa](/referencia/reports-cashflow). # Monte um painel de saldos Fonte: https://docs.ruralzap.com.br/receitas/saldos Consulte carteiras e exiba a posição financeira por moeda. ## Objetivo e pré-requisitos [#objetivo-e-pré-requisitos] Mostrar os saldos correntes do Space no seu sistema. Você precisa de uma integração habilitada com `balances:read`, uma chave no servidor e as [variáveis configuradas](/comecar). ## 1. Confirme o Space [#1-confirme-o-space] Consulte [contexto](/referencia/context) e confirme `spaceId` e as capacidades. ## 2. Busque os saldos [#2-busque-os-saldos] Use o [exemplo executável de saldos](/examples/balances.py) ou execute: ```bash curl --fail-with-body "$RURALZAP_BASE_URL/api/v1/integration/balances" \ -H "Authorization: Bearer $RURALZAP_API_KEY" ``` ## 3. Monte a apresentação [#3-monte-a-apresentação] Mapeie cada item de `data` por `id`. Exiba `name`, `currency` e `balance`. Identifique o instante `generatedAt`. Use `totals` para totais separados por moeda. ## Resultado esperado [#resultado-esperado] Um painel com carteiras ativas e saldos correntes. O total inclui carteiras retornadas mesmo quando `includeInNetWorth` é falso. O campo informa participação no patrimônio do produto, não ausência da carteira na resposta. ## Erros comuns [#erros-comuns] 401 exige revisar chave/ambiente; 403 exige escopo e acesso. Uma resposta sem carteiras é válida. Não apresente dados antigos como consulta atual quando houver erro. ## Próximos passos [#próximos-passos] [Experimente os dados sintéticos](/demonstracao) e confira a [referência de saldos](/referencia/balances). # Consultar saldos correntes Fonte: https://docs.ruralzap.com.br/referencia/balances GET /api/v1/integration/balances Requer balances:read. Inclui saldo inicial, ajustes e liquidações; exclui pendentes, compras de cartão não pagas e carteiras arquivadas. Não é projeção nem saldo bancário em tempo real. ## Autenticação [#autenticação] Authorization: Bearer. A chave determina o Space. Confira [permissões](/guias/autenticacao). ## Parâmetros [#parâmetros] Esta consulta não recebe parâmetros de query. ## cURL [#curl] ```bash curl --fail-with-body "$RURALZAP_BASE_URL/api/v1/integration/balances" \ -H "Authorization: Bearer $RURALZAP_API_KEY" ``` ## TypeScript [#typescript] ```typescript // Execute no servidor com Node.js 22+ e tsx. Não registre o payload financeiro. const base = process.env.RURALZAP_BASE_URL; const key = process.env.RURALZAP_API_KEY; if (!base || !key) throw new Error('Configure RURALZAP_BASE_URL e RURALZAP_API_KEY.'); const origin = new URL(base); if (origin.protocol !== 'https:' || origin.username || origin.password || origin.pathname !== '/' || origin.search || origin.hash) throw new Error('Informe uma origem HTTPS sem caminho ou credenciais.'); const response = await fetch(new URL('/api/v1/integration/balances', origin), { headers: { Authorization: `Bearer ${key}` }, signal: AbortSignal.timeout(30000), redirect: 'error', }); if (!response.ok) throw new Error(`HTTP ${response.status}; consulte /guias/erros.`); const data: unknown = await response.json(); // Valide data com /openapi.json antes de persistir. Preserve decimais como strings. export { data }; ``` ## Python [#python] ```python """Chamada única, Python 3, servidor. Não registra respostas financeiras.""" import json import os import urllib.request from urllib.parse import urlsplit base = os.environ['RURALZAP_BASE_URL'] key = os.environ['RURALZAP_API_KEY'] origin = urlsplit(base) if origin.scheme != 'https' or not origin.netloc or origin.username or origin.password or origin.path not in ('', '/') or origin.query or origin.fragment: raise ValueError('Informe uma origem HTTPS sem caminho ou credenciais.') class NoRedirect(urllib.request.HTTPRedirectHandler): def redirect_request(self, req, fp, code, msg, headers, newurl): return None request = urllib.request.Request(base.rstrip('/') + '/api/v1/integration/balances', headers={'Authorization': 'Bearer ' + key}) with urllib.request.build_opener(NoRedirect).open(request, timeout=30) as response: data = json.load(response) # Valide data com /openapi.json. Preserve dinheiro como string ou Decimal. ``` ## Resposta 200 [#resposta-200] Exemplo sintético, sem dados de clientes. ```json { "generatedAt": "2026-10-03T12:00:00.000Z", "data": [ { "id": "019a1000-0000-7000-8000-000000000001", "name": "Carteira sintética A", "type": "CHECKING", "currency": "BRL", "includeInNetWorth": true, "balance": "1234.5678" }, { "id": "019a1000-0000-7000-8000-000000000002", "name": "Carteira sintética B", "type": "CHECKING", "currency": "BRL", "includeInNetWorth": false, "balance": "-34.5678" }, { "id": "019a1000-0000-7000-8000-000000000003", "name": "Carteira sintética C", "type": "CHECKING", "currency": "USD", "includeInNetWorth": true, "balance": "5.0001" } ], "totals": [ { "currency": "BRL", "balance": "1200.0000" }, { "currency": "USD", "balance": "5.0001" } ] } ``` ### Campos [#campos] | Campo | Tipo | Obrigatório | Significado | | -------------------------- | ------- | ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ | | `generatedAt` | string | Sim | date-time | | `data` | array | Sim | Carteiras ativas; não inclui carteiras arquivadas nem limite disponível de cartão. | | `data[].id` | string | Sim | uuid | | `data[].name` | string | Sim | | | `data[].type` | string | Sim | Tipo de carteira do domínio. | | `data[].currency` | string | Sim | Moeda do recurso; valores de moedas distintas não são somados. | | `data[].includeInNetWorth` | boolean | Sim | Indica inclusão da carteira no patrimônio do produto. | | `data[].balance` | string | Sim | Saldo corrente persistido pelo domínio: inclui saldo inicial, ajustes e liquidações; exclui pendentes, canceladas e compras de cartão ainda não pagas. | | `totals` | array | Sim | Soma dos saldos das carteiras retornadas, por moeda, inclusive carteiras fora do patrimônio. | | `totals[].currency` | string | Sim | | | `totals[].balance` | string | Sim | Valor decimal exato com quatro casas; não converter para float. | ## Erros [#erros] | HTTP | Descrição | | ---- | ------------------------------------------------------------ | | 400 | Parâmetros inválidos ou moeda não suportada | | 401 | Credencial inválida, expirada, revogada ou de outro ambiente | | 403 | Permissão ou acesso ao recurso indisponível | | 404 | Filtro ou recurso fora do Space | | 429 | Limite excedido; respeite Retry-After | | 503 | Indisponibilidade temporária | Consulte [causas e soluções](/guias/erros). Erros públicos usam error.code, error.message e error.requestId. Em 429, aguarde Retry-After. ## Downloads [#downloads] [cURL](/examples/balances.sh) · [TypeScript](/examples/balances.ts) · [Python](/examples/balances.py) · [OpenAPI](/openapi.json) # Consultar contexto da integração Fonte: https://docs.ruralzap.com.br/referencia/context GET /api/v1/integration/context A credencial determina o Space. x-space-id não seleciona nem amplia acesso. ## Autenticação [#autenticação] Authorization: Bearer. A chave determina o Space. Confira [permissões](/guias/autenticacao). ## Parâmetros [#parâmetros] Esta consulta não recebe parâmetros de query. ## cURL [#curl] ```bash curl --fail-with-body "$RURALZAP_BASE_URL/api/v1/integration/context" \ -H "Authorization: Bearer $RURALZAP_API_KEY" ``` ## TypeScript [#typescript] ```typescript // Execute no servidor com Node.js 22+ e tsx. Não registre o payload financeiro. const base = process.env.RURALZAP_BASE_URL; const key = process.env.RURALZAP_API_KEY; if (!base || !key) throw new Error('Configure RURALZAP_BASE_URL e RURALZAP_API_KEY.'); const origin = new URL(base); if (origin.protocol !== 'https:' || origin.username || origin.password || origin.pathname !== '/' || origin.search || origin.hash) throw new Error('Informe uma origem HTTPS sem caminho ou credenciais.'); const response = await fetch(new URL('/api/v1/integration/context', origin), { headers: { Authorization: `Bearer ${key}` }, signal: AbortSignal.timeout(30000), redirect: 'error', }); if (!response.ok) throw new Error(`HTTP ${response.status}; consulte /guias/erros.`); const data: unknown = await response.json(); // Valide data com /openapi.json antes de persistir. Preserve decimais como strings. export { data }; ``` ## Python [#python] ```python """Chamada única, Python 3, servidor. Não registra respostas financeiras.""" import json import os import urllib.request from urllib.parse import urlsplit base = os.environ['RURALZAP_BASE_URL'] key = os.environ['RURALZAP_API_KEY'] origin = urlsplit(base) if origin.scheme != 'https' or not origin.netloc or origin.username or origin.password or origin.path not in ('', '/') or origin.query or origin.fragment: raise ValueError('Informe uma origem HTTPS sem caminho ou credenciais.') class NoRedirect(urllib.request.HTTPRedirectHandler): def redirect_request(self, req, fp, code, msg, headers, newurl): return None request = urllib.request.Request(base.rstrip('/') + '/api/v1/integration/context', headers={'Authorization': 'Bearer ' + key}) with urllib.request.build_opener(NoRedirect).open(request, timeout=30) as response: data = json.load(response) # Valide data com /openapi.json. Preserve dinheiro como string ou Decimal. ``` ## Resposta 200 [#resposta-200] Exemplo sintético, sem dados de clientes. ```json { "integrationId": "019a1000-0000-7000-8000-000000000001", "spaceId": "019a1000-0000-7000-8000-000000000001", "scopes": [ "balances:read" ], "capabilities": [ "context", "wallets", "balances" ] } ``` ### Campos [#campos] | Campo | Tipo | Obrigatório | Significado | | --------------- | ------ | ----------- | -------------------------------------------------------------- | | `integrationId` | string | Sim | uuid | | `spaceId` | string | Sim | uuid | | `scopes` | array | Sim | | | `capabilities` | array | Sim | Rotas disponíveis na interseção dos escopos e direitos atuais. | ## Erros [#erros] | HTTP | Descrição | | ---- | ------------------------------------------------------------ | | 400 | Parâmetros inválidos ou moeda não suportada | | 401 | Credencial inválida, expirada, revogada ou de outro ambiente | | 403 | Permissão ou acesso ao recurso indisponível | | 404 | Filtro ou recurso fora do Space | | 429 | Limite excedido; respeite Retry-After | | 503 | Indisponibilidade temporária | Consulte [causas e soluções](/guias/erros). Erros públicos usam error.code, error.message e error.requestId. Em 429, aguarde Retry-After. ## Downloads [#downloads] [cURL](/examples/context.sh) · [TypeScript](/examples/context.ts) · [Python](/examples/context.py) · [OpenAPI](/openapi.json) # Referência da API Fonte: https://docs.ruralzap.com.br/referencia Seis consultas de leitura, geradas dos controllers e DTOs públicos. A origem de produção é `https://api.finance.meyje.com.br`. Todas as chamadas exigem `Authorization: Bearer`. A chave identifica um Space. | Consulta | Endpoint | | ---------------------------------------------- | ---------------------------------------- | | [Contexto](/referencia/context) | GET /api/v1/integration/context | | [Carteiras](/referencia/wallets) | GET /api/v1/integration/wallets | | [Saldos](/referencia/balances) | GET /api/v1/integration/balances | | [Lançamentos](/referencia/transactions) | GET /api/v1/integration/transactions | | [Resumo](/referencia/reports-summary) | GET /api/v1/integration/reports/summary | | [Fluxo de caixa](/referencia/reports-cashflow) | GET /api/v1/integration/reports/cashflow | Baixe o [OpenAPI](/openapi.json) ou importe a [coleção Postman](/postman.json). No Postman, mantenha `apiKey` em um ambiente privado. Nunca compartilhe seu valor. # Consultar fluxo de caixa realizado Fonte: https://docs.ruralzap.com.br/referencia/reports-cashflow GET /api/v1/integration/reports/cashflow Requer reports:read e CASHFLOW_REPORT. Período máximo 366 dias. Mesmo cálculo do relatório do produto, com valores decimais exatos. groupBy: day, week ou month. Não inclui projeções de pendentes. ## Autenticação [#autenticação] Authorization: Bearer. A chave determina o Space. Confira [permissões](/guias/autenticacao). ## Parâmetros [#parâmetros] | Nome | Obrigatório | Tipo | Detalhes | | -------------- | ----------- | ------ | --------------------------------------------------------------------------------------------------------------------------------------------- | | `startDate` | Sim | string | Data financeira inicial inclusiva. Período máximo: 366 dias. date | | `endDate` | Sim | string | Data financeira final inclusiva. date | | `walletId` | Não | string | Carteira do Space. Inclui transferências de entrada e saída dessa carteira. uuid | | `categoryId` | Não | string | Categoria do Space ou categoria compartilhada do seu reseller. uuid | | `costCenterId` | Não | string | Centro(s) de custo por UUID separado por vírgula ou UNCLASSIFIED. Em composições, deve corresponder à mesma parte da categoria e equipamento. | | `assetId` | Não | string | Equipamento do Space atribuído à mesma parte da categoria e centro. uuid | | `groupBy` | Não | string | day, week, month Padrão: month | ## cURL [#curl] ```bash curl --fail-with-body "$RURALZAP_BASE_URL/api/v1/integration/reports/cashflow?startDate=2026-01-01&endDate=2026-01-31" \ -H "Authorization: Bearer $RURALZAP_API_KEY" ``` ## TypeScript [#typescript] ```typescript // Execute no servidor com Node.js 22+ e tsx. Não registre o payload financeiro. const base = process.env.RURALZAP_BASE_URL; const key = process.env.RURALZAP_API_KEY; if (!base || !key) throw new Error('Configure RURALZAP_BASE_URL e RURALZAP_API_KEY.'); const origin = new URL(base); if (origin.protocol !== 'https:' || origin.username || origin.password || origin.pathname !== '/' || origin.search || origin.hash) throw new Error('Informe uma origem HTTPS sem caminho ou credenciais.'); const response = await fetch(new URL('/api/v1/integration/reports/cashflow?startDate=2026-01-01&endDate=2026-01-31', origin), { headers: { Authorization: `Bearer ${key}` }, signal: AbortSignal.timeout(30000), redirect: 'error', }); if (!response.ok) throw new Error(`HTTP ${response.status}; consulte /guias/erros.`); const data: unknown = await response.json(); // Valide data com /openapi.json antes de persistir. Preserve decimais como strings. export { data }; ``` ## Python [#python] ```python """Chamada única, Python 3, servidor. Não registra respostas financeiras.""" import json import os import urllib.request from urllib.parse import urlsplit base = os.environ['RURALZAP_BASE_URL'] key = os.environ['RURALZAP_API_KEY'] origin = urlsplit(base) if origin.scheme != 'https' or not origin.netloc or origin.username or origin.password or origin.path not in ('', '/') or origin.query or origin.fragment: raise ValueError('Informe uma origem HTTPS sem caminho ou credenciais.') class NoRedirect(urllib.request.HTTPRedirectHandler): def redirect_request(self, req, fp, code, msg, headers, newurl): return None request = urllib.request.Request(base.rstrip('/') + '/api/v1/integration/reports/cashflow?startDate=2026-01-01&endDate=2026-01-31', headers={'Authorization': 'Bearer ' + key}) with urllib.request.build_opener(NoRedirect).open(request, timeout=30) as response: data = json.load(response) # Valide data com /openapi.json. Preserve dinheiro como string ou Decimal. ``` ## Resposta 200 [#resposta-200] Exemplo sintético, sem dados de clientes. ```json { "meta": { "generatedAt": "2026-10-03T12:00:00.000Z", "startDate": "2026-01-01", "endDate": "2026-01-31", "timezone": "America/Sao_Paulo", "walletId": null, "categoryId": null, "costCenterId": null, "assetId": null, "mode": "cash", "groupBy": "month" }, "currency": "BRL", "summary": { "openingBalance": "1000.0000", "totalInflows": "600.0000", "totalOutflows": "400.0000", "netCashflow": "200.0000", "totalAdjustments": "0.0000", "closingBalance": "1200.0000" }, "data": [ { "period": "2026-01", "inflows": "600.0000", "outflows": "400.0000", "netFlow": "200.0000", "adjustments": "0.0000", "runningBalance": "1200.0000" } ] } ``` ### Campos [#campos] | Campo | Tipo | Obrigatório | Significado | | ----------------------- | -------------- | ----------- | -------------------------------------------------------------------------------------------------------------------------------- | | `meta` | object | Sim | | | `meta.generatedAt` | string | Sim | date-time | | `meta.startDate` | string | Sim | date | | `meta.endDate` | string | Sim | date | | `meta.timezone` | string | Sim | Referência de negócio. Datas financeiras são date-only e não sofrem conversão de fuso. | | `meta.walletId` | string ou null | Sim | uuid Aceita null. | | `meta.categoryId` | string ou null | Sim | uuid Aceita null. | | `meta.costCenterId` | string ou null | Sim | Aceita null. | | `meta.assetId` | string ou null | Sim | uuid Aceita null. | | `meta.mode` | string | Sim | cash é a visão completa das carteiras; slice é recorte gerencial e não equivale ao saldo bancário integral. Valores: cash, slice | | `meta.groupBy` | string | Sim | Valores: day, week, month | | `currency` | string | Sim | Relatórios suportam BRL; uma combinação de moedas não é convertida nem somada. | | `summary` | string | Sim | Resumo do fluxo de caixa realizado. Requer o recurso CASHFLOW_REPORT. | | `data` | array | Sim | | | `data[].period` | string | Sim | Chave canônica do período; períodos sem movimentos podem estar ausentes. | | `data[].inflows` | string | Sim | Valor decimal exato com quatro casas; não converter para float. | | `data[].outflows` | string | Sim | Valor decimal exato com quatro casas; não converter para float. | | `data[].netFlow` | string | Sim | Valor decimal exato com quatro casas; não converter para float. | | `data[].adjustments` | string | Sim | Valor decimal exato com quatro casas; não converter para float. | | `data[].runningBalance` | string | Sim | Valor decimal exato com quatro casas; não converter para float. | ## Erros [#erros] | HTTP | Descrição | | ---- | ------------------------------------------------------------ | | 400 | Parâmetros inválidos ou moeda não suportada | | 401 | Credencial inválida, expirada, revogada ou de outro ambiente | | 403 | Permissão ou acesso ao recurso indisponível | | 404 | Filtro ou recurso fora do Space | | 429 | Limite excedido; respeite Retry-After | | 503 | Indisponibilidade temporária | Consulte [causas e soluções](/guias/erros). Erros públicos usam error.code, error.message e error.requestId. Em 429, aguarde Retry-After. ## Downloads [#downloads] [cURL](/examples/reports-cashflow.sh) · [TypeScript](/examples/reports-cashflow.ts) · [Python](/examples/reports-cashflow.py) · [OpenAPI](/openapi.json) # Consultar resumo financeiro realizado Fonte: https://docs.ruralzap.com.br/referencia/reports-summary GET /api/v1/integration/reports/summary Resumo do fluxo de caixa; requer reports:read e CASHFLOW_REPORT. Segue regras do relatório do produto, incluindo abertura, ajustes e transferências externas da carteira selecionada. Moeda suportada: BRL. ## Autenticação [#autenticação] Authorization: Bearer. A chave determina o Space. Confira [permissões](/guias/autenticacao). ## Parâmetros [#parâmetros] | Nome | Obrigatório | Tipo | Detalhes | | -------------- | ----------- | ------ | --------------------------------------------------------------------------------------------------------------------------------------------- | | `startDate` | Sim | string | Data financeira inicial inclusiva. Período máximo: 366 dias. date | | `endDate` | Sim | string | Data financeira final inclusiva. date | | `walletId` | Não | string | Carteira do Space. Inclui transferências de entrada e saída dessa carteira. uuid | | `categoryId` | Não | string | Categoria do Space ou categoria compartilhada do seu reseller. uuid | | `costCenterId` | Não | string | Centro(s) de custo por UUID separado por vírgula ou UNCLASSIFIED. Em composições, deve corresponder à mesma parte da categoria e equipamento. | | `assetId` | Não | string | Equipamento do Space atribuído à mesma parte da categoria e centro. uuid | | `groupBy` | Não | string | day, week, month Padrão: month | ## cURL [#curl] ```bash curl --fail-with-body "$RURALZAP_BASE_URL/api/v1/integration/reports/summary?startDate=2026-01-01&endDate=2026-01-31" \ -H "Authorization: Bearer $RURALZAP_API_KEY" ``` ## TypeScript [#typescript] ```typescript // Execute no servidor com Node.js 22+ e tsx. Não registre o payload financeiro. const base = process.env.RURALZAP_BASE_URL; const key = process.env.RURALZAP_API_KEY; if (!base || !key) throw new Error('Configure RURALZAP_BASE_URL e RURALZAP_API_KEY.'); const origin = new URL(base); if (origin.protocol !== 'https:' || origin.username || origin.password || origin.pathname !== '/' || origin.search || origin.hash) throw new Error('Informe uma origem HTTPS sem caminho ou credenciais.'); const response = await fetch(new URL('/api/v1/integration/reports/summary?startDate=2026-01-01&endDate=2026-01-31', origin), { headers: { Authorization: `Bearer ${key}` }, signal: AbortSignal.timeout(30000), redirect: 'error', }); if (!response.ok) throw new Error(`HTTP ${response.status}; consulte /guias/erros.`); const data: unknown = await response.json(); // Valide data com /openapi.json antes de persistir. Preserve decimais como strings. export { data }; ``` ## Python [#python] ```python """Chamada única, Python 3, servidor. Não registra respostas financeiras.""" import json import os import urllib.request from urllib.parse import urlsplit base = os.environ['RURALZAP_BASE_URL'] key = os.environ['RURALZAP_API_KEY'] origin = urlsplit(base) if origin.scheme != 'https' or not origin.netloc or origin.username or origin.password or origin.path not in ('', '/') or origin.query or origin.fragment: raise ValueError('Informe uma origem HTTPS sem caminho ou credenciais.') class NoRedirect(urllib.request.HTTPRedirectHandler): def redirect_request(self, req, fp, code, msg, headers, newurl): return None request = urllib.request.Request(base.rstrip('/') + '/api/v1/integration/reports/summary?startDate=2026-01-01&endDate=2026-01-31', headers={'Authorization': 'Bearer ' + key}) with urllib.request.build_opener(NoRedirect).open(request, timeout=30) as response: data = json.load(response) # Valide data com /openapi.json. Preserve dinheiro como string ou Decimal. ``` ## Resposta 200 [#resposta-200] Exemplo sintético, sem dados de clientes. ```json { "meta": { "generatedAt": "2026-10-03T12:00:00.000Z", "startDate": "2026-01-01", "endDate": "2026-01-31", "timezone": "America/Sao_Paulo", "walletId": null, "categoryId": null, "costCenterId": null, "assetId": null, "mode": "cash", "groupBy": "month" }, "currency": "BRL", "summary": { "openingBalance": "1000.0000", "totalInflows": "600.0000", "totalOutflows": "400.0000", "netCashflow": "200.0000", "totalAdjustments": "0.0000", "closingBalance": "1200.0000" } } ``` ### Campos [#campos] | Campo | Tipo | Obrigatório | Significado | | ------------------- | -------------- | ----------- | -------------------------------------------------------------------------------------------------------------------------------- | | `meta` | object | Sim | | | `meta.generatedAt` | string | Sim | date-time | | `meta.startDate` | string | Sim | date | | `meta.endDate` | string | Sim | date | | `meta.timezone` | string | Sim | Referência de negócio. Datas financeiras são date-only e não sofrem conversão de fuso. | | `meta.walletId` | string ou null | Sim | uuid Aceita null. | | `meta.categoryId` | string ou null | Sim | uuid Aceita null. | | `meta.costCenterId` | string ou null | Sim | Aceita null. | | `meta.assetId` | string ou null | Sim | uuid Aceita null. | | `meta.mode` | string | Sim | cash é a visão completa das carteiras; slice é recorte gerencial e não equivale ao saldo bancário integral. Valores: cash, slice | | `meta.groupBy` | string | Sim | Valores: day, week, month | | `currency` | string | Sim | Relatórios suportam BRL; uma combinação de moedas não é convertida nem somada. | | `summary` | string | Sim | Resumo do fluxo de caixa realizado. Requer o recurso CASHFLOW_REPORT. | ## Erros [#erros] | HTTP | Descrição | | ---- | ------------------------------------------------------------ | | 400 | Parâmetros inválidos ou moeda não suportada | | 401 | Credencial inválida, expirada, revogada ou de outro ambiente | | 403 | Permissão ou acesso ao recurso indisponível | | 404 | Filtro ou recurso fora do Space | | 429 | Limite excedido; respeite Retry-After | | 503 | Indisponibilidade temporária | Consulte [causas e soluções](/guias/erros). Erros públicos usam error.code, error.message e error.requestId. Em 429, aguarde Retry-After. ## Downloads [#downloads] [cURL](/examples/reports-summary.sh) · [TypeScript](/examples/reports-summary.ts) · [Python](/examples/reports-summary.py) · [OpenAPI](/openapi.json) # Consultar lançamentos por período Fonte: https://docs.ruralzap.com.br/referencia/transactions GET /api/v1/integration/transactions Requer transactions:read. Ordem createdAt,id crescente. Até 100 itens; período obrigatório de até 366 dias. Inclui pendentes/cancelados, ajustes, transferências e pagamentos de fatura, com flags explícitas; exclui apagados. Não somar todos os lançamentos como receita/despesa: use os relatórios. Paginação não é snapshot; alterações/exclusões durante a travessia podem modificar resultados. ## Autenticação [#autenticação] Authorization: Bearer. A chave determina o Space. Confira [permissões](/guias/autenticacao). ## Parâmetros [#parâmetros] | Nome | Obrigatório | Tipo | Detalhes | | -------------- | ----------- | ------ | --------------------------------------------------------------------------------------------------------------------------------------------- | | `startDate` | Sim | string | Data financeira inicial inclusiva. Período máximo: 366 dias. date | | `endDate` | Sim | string | Data financeira final inclusiva. date | | `walletId` | Não | string | Carteira do Space. Inclui transferências de entrada e saída dessa carteira. uuid | | `categoryId` | Não | string | Categoria do Space ou categoria compartilhada do seu reseller. uuid | | `costCenterId` | Não | string | Centro(s) de custo por UUID separado por vírgula ou UNCLASSIFIED. Em composições, deve corresponder à mesma parte da categoria e equipamento. | | `assetId` | Não | string | Equipamento do Space atribuído à mesma parte da categoria e centro. uuid | | `type` | Não | string | INCOME, EXPENSE, TRANSFER | | `status` | Não | string | PENDING, COMPLETED, CANCELLED | | `limit` | Não | number | Mínimo: 1 Máximo: 100 Padrão: 50 | | `cursor` | Não | string | nextCursor da página anterior, mantendo todos os filtros e limite. Validade: 24 horas. Não representa snapshot nem sincronização incremental. | ## cURL [#curl] ```bash curl --fail-with-body "$RURALZAP_BASE_URL/api/v1/integration/transactions?startDate=2026-01-01&endDate=2026-01-31" \ -H "Authorization: Bearer $RURALZAP_API_KEY" ``` ## TypeScript [#typescript] ```typescript // Execute no servidor com Node.js 22+ e tsx. Não registre o payload financeiro. const base = process.env.RURALZAP_BASE_URL; const key = process.env.RURALZAP_API_KEY; if (!base || !key) throw new Error('Configure RURALZAP_BASE_URL e RURALZAP_API_KEY.'); const origin = new URL(base); if (origin.protocol !== 'https:' || origin.username || origin.password || origin.pathname !== '/' || origin.search || origin.hash) throw new Error('Informe uma origem HTTPS sem caminho ou credenciais.'); const response = await fetch(new URL('/api/v1/integration/transactions?startDate=2026-01-01&endDate=2026-01-31', origin), { headers: { Authorization: `Bearer ${key}` }, signal: AbortSignal.timeout(30000), redirect: 'error', }); if (!response.ok) throw new Error(`HTTP ${response.status}; consulte /guias/erros.`); const data: unknown = await response.json(); // Valide data com /openapi.json antes de persistir. Preserve decimais como strings. export { data }; ``` ## Python [#python] ```python """Chamada única, Python 3, servidor. Não registra respostas financeiras.""" import json import os import urllib.request from urllib.parse import urlsplit base = os.environ['RURALZAP_BASE_URL'] key = os.environ['RURALZAP_API_KEY'] origin = urlsplit(base) if origin.scheme != 'https' or not origin.netloc or origin.username or origin.password or origin.path not in ('', '/') or origin.query or origin.fragment: raise ValueError('Informe uma origem HTTPS sem caminho ou credenciais.') class NoRedirect(urllib.request.HTTPRedirectHandler): def redirect_request(self, req, fp, code, msg, headers, newurl): return None request = urllib.request.Request(base.rstrip('/') + '/api/v1/integration/transactions?startDate=2026-01-01&endDate=2026-01-31', headers={'Authorization': 'Bearer ' + key}) with urllib.request.build_opener(NoRedirect).open(request, timeout=30) as response: data = json.load(response) # Valide data com /openapi.json. Preserve dinheiro como string ou Decimal. ``` ## Resposta 200 [#resposta-200] Exemplo sintético, sem dados de clientes. ```json { "data": [ { "id": "019a1000-0000-7000-8000-000000000001", "reference": "#105", "type": "INCOME", "status": "COMPLETED", "amount": "100.0000", "reportAmount": "1234.5678", "compositionVersion": 0, "compositionLines": [], "currency": "BRL", "description": "Venda sintética de grãos", "date": "2026-01-15", "competenceDate": null, "walletId": null, "categoryId": null, "categoryName": null, "cardId": null, "transferSourceWalletId": null, "transferDestinationWalletId": null, "isAdjustment": false, "isInvoicePayment": false, "ignored": false, "settlementManaged": false, "settledPrincipal": "100.0000", "settledCashAmount": "100.0000", "remainingAmount": "0.0000", "settlementStatus": "PAID", "createdAt": "2026-10-03T12:00:00.000Z", "updatedAt": "2026-10-03T12:00:00.000Z" }, { "id": "019a1000-0000-7000-8000-000000000002", "reference": "#105", "type": "EXPENSE", "status": "COMPLETED", "amount": "200.0000", "reportAmount": "1234.5678", "compositionVersion": 0, "compositionLines": [], "currency": "BRL", "description": "Compra sintética de insumos", "date": "2026-01-15", "competenceDate": null, "walletId": null, "categoryId": null, "categoryName": null, "cardId": null, "transferSourceWalletId": null, "transferDestinationWalletId": null, "isAdjustment": false, "isInvoicePayment": false, "ignored": false, "settlementManaged": false, "settledPrincipal": "200.0000", "settledCashAmount": "200.0000", "remainingAmount": "0.0000", "settlementStatus": "PAID", "createdAt": "2026-10-03T12:00:00.000Z", "updatedAt": "2026-10-03T12:00:00.000Z" }, { "id": "019a1000-0000-7000-8000-000000000003", "reference": "#105", "type": "INCOME", "status": "COMPLETED", "amount": "300.0000", "reportAmount": "1234.5678", "compositionVersion": 0, "compositionLines": [], "currency": "BRL", "description": "Serviço sintético", "date": "2026-01-15", "competenceDate": null, "walletId": null, "categoryId": null, "categoryName": null, "cardId": null, "transferSourceWalletId": null, "transferDestinationWalletId": null, "isAdjustment": false, "isInvoicePayment": false, "ignored": false, "settlementManaged": false, "settledPrincipal": "300.0000", "settledCashAmount": "300.0000", "remainingAmount": "0.0000", "settlementStatus": "PAID", "createdAt": "2026-10-03T12:00:00.000Z", "updatedAt": "2026-10-03T12:00:00.000Z" } ], "meta": { "hasMore": false, "nextCursor": null } } ``` ### Campos [#campos] | Campo | Tipo | Obrigatório | Significado | | ------------------------------------------ | -------------- | ----------- | ------------------------------------------------------------------------------------------------------ | | `data` | array | Sim | | | `data[].id` | string | Sim | uuid | | `data[].reference` | string ou null | Sim | Referência humana; use id como identificador estável. Aceita null. | | `data[].type` | string | Sim | Valores: INCOME, EXPENSE, TRANSFER | | `data[].status` | string | Sim | Valores: PENDING, COMPLETED, CANCELLED | | `data[].amount` | string | Sim | Principal original integral do lançamento, preservado mesmo em recortes analíticos. | | `data[].reportAmount` | string | Sim | Principal considerado pelas partes que atendem simultaneamente aos filtros. Não representa caixa pago. | | `data[].compositionVersion` | number | Sim | Zero identifica classificação legada; versão positiva usa exclusivamente compositionLines. | | `data[].compositionLines` | array | Sim | Composição completa do lançamento para auditoria; não somente as partes filtradas. | | `data[].compositionLines[].id` | string | Sim | uuid | | `data[].compositionLines[].position` | number | Sim | | | `data[].compositionLines[].amount` | string | Sim | Valor exato da parte no principal contratado. | | `data[].compositionLines[].categoryId` | string ou null | Sim | uuid Aceita null. | | `data[].compositionLines[].categoryName` | string ou null | Sim | Aceita null. | | `data[].compositionLines[].costCenterId` | string ou null | Sim | uuid Aceita null. | | `data[].compositionLines[].costCenterName` | string ou null | Sim | Aceita null. | | `data[].compositionLines[].equipmentState` | string | Sim | Valores: NONE, PENDING, LINKED | | `data[].compositionLines[].assetId` | string ou null | Sim | uuid Aceita null. | | `data[].compositionLines[].assetCode` | string ou null | Sim | Aceita null. | | `data[].compositionLines[].assetName` | string ou null | Sim | Aceita null. | | `data[].currency` | string | Sim | | | `data[].description` | string ou null | Sim | Aceita null. | | `data[].date` | string | Sim | date | | `data[].competenceDate` | string ou null | Sim | date Aceita null. | | `data[].walletId` | string ou null | Sim | uuid Aceita null. | | `data[].categoryId` | string ou null | Sim | uuid Aceita null. | | `data[].categoryName` | string ou null | Sim | Aceita null. | | `data[].cardId` | string ou null | Sim | uuid Aceita null. | | `data[].transferSourceWalletId` | string ou null | Sim | uuid Aceita null. | | `data[].transferDestinationWalletId` | string ou null | Sim | uuid Aceita null. | | `data[].isAdjustment` | boolean | Sim | | | `data[].isInvoicePayment` | boolean | Sim | | | `data[].ignored` | boolean | Sim | Lançamento desconsiderado dos indicadores, ainda visível e podendo afetar saldo. | | `data[].settlementManaged` | boolean | Sim | Indica liquidações parciais geridas pelo domínio. | | `data[].settledPrincipal` | string | Sim | Valor decimal exato com quatro casas; não converter para float. | | `data[].settledCashAmount` | string | Sim | Valor decimal exato com quatro casas; não converter para float. | | `data[].remainingAmount` | string | Sim | Valor decimal exato com quatro casas; não converter para float. | | `data[].settlementStatus` | string | Sim | Valores: PAID, PARTIAL, UNPAID | | `data[].createdAt` | string | Sim | date-time | | `data[].updatedAt` | string | Sim | Atualização técnica; não equivale a feed de mudanças. date-time | | `meta` | object | Sim | | | `meta.nextCursor` | string ou null | Sim | Aceita null. | | `meta.hasMore` | boolean | Sim | | ## Erros [#erros] | HTTP | Descrição | | ---- | ------------------------------------------------------------ | | 400 | Parâmetros inválidos ou moeda não suportada | | 401 | Credencial inválida, expirada, revogada ou de outro ambiente | | 403 | Permissão ou acesso ao recurso indisponível | | 404 | Filtro ou recurso fora do Space | | 429 | Limite excedido; respeite Retry-After | | 503 | Indisponibilidade temporária | Consulte [causas e soluções](/guias/erros). Erros públicos usam error.code, error.message e error.requestId. Em 429, aguarde Retry-After. ## Downloads [#downloads] [cURL](/examples/transactions.sh) · [TypeScript](/examples/transactions.ts) · [Python](/examples/transactions.py) · [OpenAPI](/openapi.json) # Listar carteiras ativas Fonte: https://docs.ruralzap.com.br/referencia/wallets GET /api/v1/integration/wallets Requer balances:read. Retorna referências financeiras mínimas, sem dados bancários privados. ## Autenticação [#autenticação] Authorization: Bearer. A chave determina o Space. Confira [permissões](/guias/autenticacao). ## Parâmetros [#parâmetros] Esta consulta não recebe parâmetros de query. ## cURL [#curl] ```bash curl --fail-with-body "$RURALZAP_BASE_URL/api/v1/integration/wallets" \ -H "Authorization: Bearer $RURALZAP_API_KEY" ``` ## TypeScript [#typescript] ```typescript // Execute no servidor com Node.js 22+ e tsx. Não registre o payload financeiro. const base = process.env.RURALZAP_BASE_URL; const key = process.env.RURALZAP_API_KEY; if (!base || !key) throw new Error('Configure RURALZAP_BASE_URL e RURALZAP_API_KEY.'); const origin = new URL(base); if (origin.protocol !== 'https:' || origin.username || origin.password || origin.pathname !== '/' || origin.search || origin.hash) throw new Error('Informe uma origem HTTPS sem caminho ou credenciais.'); const response = await fetch(new URL('/api/v1/integration/wallets', origin), { headers: { Authorization: `Bearer ${key}` }, signal: AbortSignal.timeout(30000), redirect: 'error', }); if (!response.ok) throw new Error(`HTTP ${response.status}; consulte /guias/erros.`); const data: unknown = await response.json(); // Valide data com /openapi.json antes de persistir. Preserve decimais como strings. export { data }; ``` ## Python [#python] ```python """Chamada única, Python 3, servidor. Não registra respostas financeiras.""" import json import os import urllib.request from urllib.parse import urlsplit base = os.environ['RURALZAP_BASE_URL'] key = os.environ['RURALZAP_API_KEY'] origin = urlsplit(base) if origin.scheme != 'https' or not origin.netloc or origin.username or origin.password or origin.path not in ('', '/') or origin.query or origin.fragment: raise ValueError('Informe uma origem HTTPS sem caminho ou credenciais.') class NoRedirect(urllib.request.HTTPRedirectHandler): def redirect_request(self, req, fp, code, msg, headers, newurl): return None request = urllib.request.Request(base.rstrip('/') + '/api/v1/integration/wallets', headers={'Authorization': 'Bearer ' + key}) with urllib.request.build_opener(NoRedirect).open(request, timeout=30) as response: data = json.load(response) # Valide data com /openapi.json. Preserve dinheiro como string ou Decimal. ``` ## Resposta 200 [#resposta-200] Exemplo sintético, sem dados de clientes. ```json { "data": [ { "id": "019a1000-0000-7000-8000-000000000001", "name": "Carteira sintética A", "type": "CHECKING", "currency": "BRL", "includeInNetWorth": true }, { "id": "019a1000-0000-7000-8000-000000000002", "name": "Carteira sintética B", "type": "CHECKING", "currency": "BRL", "includeInNetWorth": false }, { "id": "019a1000-0000-7000-8000-000000000003", "name": "Carteira sintética C", "type": "CHECKING", "currency": "USD", "includeInNetWorth": true } ] } ``` ### Campos [#campos] | Campo | Tipo | Obrigatório | Significado | | -------------------------- | ------- | ----------- | -------------------------------------------------------------- | | `data` | array | Sim | | | `data[].id` | string | Sim | uuid | | `data[].name` | string | Sim | | | `data[].type` | string | Sim | Tipo de carteira do domínio. | | `data[].currency` | string | Sim | Moeda do recurso; valores de moedas distintas não são somados. | | `data[].includeInNetWorth` | boolean | Sim | Indica inclusão da carteira no patrimônio do produto. | ## Erros [#erros] | HTTP | Descrição | | ---- | ------------------------------------------------------------ | | 400 | Parâmetros inválidos ou moeda não suportada | | 401 | Credencial inválida, expirada, revogada ou de outro ambiente | | 403 | Permissão ou acesso ao recurso indisponível | | 404 | Filtro ou recurso fora do Space | | 429 | Limite excedido; respeite Retry-After | | 503 | Indisponibilidade temporária | Consulte [causas e soluções](/guias/erros). Erros públicos usam error.code, error.message e error.requestId. Em 429, aguarde Retry-After. ## Downloads [#downloads] [cURL](/examples/wallets.sh) · [TypeScript](/examples/wallets.ts) · [Python](/examples/wallets.py) · [OpenAPI](/openapi.json) # Ajude a melhorar a integração Fonte: https://docs.ruralzap.com.br/sugestoes Relate dificuldades com contexto suficiente para resolvermos o problema. ## Encontrou algo confuso? [#encontrou-algo-confuso] Use **Reportar problema nesta página**, no início do conteúdo em que encontrou a dificuldade. O modelo inclui a URL, seu objetivo e o comportamento esperado. Envie o relato pelo suporte disponível no [RuralZap](https://agro.ruralzap.com.br). A equipe pode transformar a demanda em melhoria de documentação ou produto. ## O que incluir [#o-que-incluir] * Página ou endpoint consultado. * O que você estava tentando integrar. * Resultado esperado e dificuldade encontrada. * Status HTTP e identificador da requisição, quando disponíveis. Não envie chaves, tokens ou respostas financeiras. Use exemplos sintéticos para explicar o cenário. ## Propor uma nova integração [#propor-uma-nova-integração] Descreva o sistema de destino, os dados necessários e a frequência de atualização desejada. Uma sugestão não representa compromisso de implementação nem prazo de entrega.