Openi DeveloperDeveloper
Guia de integração

Fluxo de ingestão

Como criar data sources, selecionar dados, configurar datasets/fields e iniciar conciliações.

O Nexus sempre transforma uma origem externa em records normalizados dentro de um dataset. A partir desses records, os fields extraem chaves canônicas e os rule sets comparam dois datasets.

O fluxo recomendado para um novo cliente é:

[1] Escolher o tipo de data source
         │
         ▼
[2] Criar o data source e testar a conectividade
         │
         ▼
[3] Criar ou selecionar o dataset de destino
         │
         ▼
[4] Configurar fields canônicos antes da carga real
         │
         ▼
[5] Ingerir dados: webhook, import de arquivo, sync ou consulta Postgres
         │
         ▼
[6] Criar rule set ligando dois datasets e executar matching

Configure os fields antes da primeira carga produtiva sempre que possível. Sem fields, os records podem ser gravados, mas as regras de matching não terão chaves canônicas confiáveis para comparar.

Escolha do data source

TipoQuando usarComo os records entram
webhookSeu sistema consegue enviar eventos JSON para o Nexus em tempo real.POST /hooks/{slug} cria/atualiza records e dispara matching automático.
postgresOs dados estão em tabelas PostgreSQL acessíveis pelo Nexus.O Nexus navega schemas/tabelas, enfileira uma ingestão e lê as linhas selecionadas.
fileO cliente fornece CSV/XLSX recorrente ou arquivos Francesinha (.txt/.fra).Upload multipart, depois import para dataset. Francesinha é processada automaticamente.
openfinanceO cliente quer conciliar transações vindas do conector OpenFinance.Sync busca contas/cartões/investimentos e transações; webhooks do provedor atualizam eventos novos.
openiO cliente usa dados internos Openi, como notas e lançamentos contábeis.Sync busca invoices/accounting entries e cria datasets padrão.

Para qualquer tipo, as rotas /v1/* exigem x-api-key. Apenas /hooks/{slug} usa X-Webhook-Secret.

1. Criar data source

Webhook

POST /v1/data-sources

{
  "type": "webhook",
  "name": "transacoes_banco_x",
  "config": {
    "secret": "um-segredo-com-no-minimo-16-chars",
    "slug": "transacoes-banco-x"
  }
}

Resposta:

{
  "id": "8a8f0e8c-3a2c-4e0f-9c0c-1d4d9b8e2c11",
  "type": "webhook",
  "name": "transacoes_banco_x",
  "created_at": "2026-05-06T14:00:00.000Z",
  "webhook_url": "/hooks/transacoes-banco-x",
  "secret_plain": "um-segredo-com-no-minimo-16-chars",
  "status": "pending_first_sample",
  "listening_until": "2026-05-06T14:05:00.000Z"
}

Pontos importantes:

  • secret_plain só é devolvido nesta resposta. Armazene o valor em um cofre.
  • config.slug é opcional. Se omitido, o Nexus gera um wh-....
  • O primeiro payload precisa chegar em até 5 minutos. Se a janela expirar, /hooks/{slug} retorna 409 WINDOW_EXPIRED.
  • PATCH /v1/data-sources/{id} pode alterar o name ou o slug.

Postgres

Use connectionString ou campos discretos:

{
  "type": "postgres",
  "name": "erp_postgres",
  "config": {
    "host": "db.cliente.com.br",
    "port": 5432,
    "database": "erp",
    "user": "nexus_reader",
    "password": "senha",
    "ssl": true,
    "rejectUnauthorized": true
  }
}

Depois de criar, valide a conexão:

curl -sS -X POST https://<API_BASE>/v1/data-sources/<DATA_SOURCE_ID>/test \
  -H "x-api-key: $NEXUS_API_KEY"

Para explorar a origem antes de importar:

GET  /v1/data-sources/{id}/browse/schemas
GET  /v1/data-sources/{id}/browse/tables?schema=public
GET  /v1/data-sources/{id}/browse/columns?schema=public&table=transactions
POST /v1/data-sources/{id}/browse/preview

Arquivos CSV/XLSX/Francesinha

Crie um data source de arquivo:

{
  "type": "file",
  "name": "arquivos_erp",
  "config": {
    "description": "Arquivos mensais enviados pelo ERP"
  }
}

Esse tipo aceita upload de CSV, XLSX e Francesinha (.txt/.fra) em /v1/data-sources/{id}/files.

OpenFinance

{
  "type": "openfinance",
  "name": "openfinance_cliente",
  "config": {
    "openfinanceUserId": "tenant-openfinance",
    "itemId": "item_123",
    "authorizationKey": "token-do-provedor",
    "baseUrl": "https://dev-of.openi.com.br/v1"
  }
}
  • baseUrl é opcional quando o ambiente do Nexus já define a URL padrão.
  • Na criação, o Nexus tenta garantir o webhook tenant-level do OpenFinance.
  • Use /v1/data-sources/openfinance/test para testar credenciais antes de criar, ou /v1/data-sources/{id}/test depois.

Openi

{
  "type": "openi",
  "name": "openi_empresa_123",
  "config": {
    "username": "usuario",
    "password": "senha",
    "companyId": "company_123"
  }
}

Ao criar, o Nexus tenta provisionar os datasets padrão openi_invoices e openi_accounting_entries e registrar o webhook com o Openi. Também existe o setup idempotente server-to-server:

POST /v1/setup/openi
POST /v1/data-sources/openi/setup-reconciliation

2. Criar ou localizar dataset

Um data source pode ter um ou mais datasets conforme o tipo e o fluxo.

  • webhook: o dataset pode ser pré-criado ou criado automaticamente no primeiro payload.
  • postgres: a ingestão cria/usa o dataset informado em datasetName; pré-crie para configurar fields antes.
  • file: crie o dataset antes do import se quiser controlar fields e mapeamento.
  • openi: datasets padrão são criados na configuração.
  • openfinance: sync/import cria datasets conforme a seleção processada pelo conector.

Criar dataset manualmente:

{
  "dataSourceId": "8a8f0e8c-3a2c-4e0f-9c0c-1d4d9b8e2c11",
  "name": "transacoes_banco_x",
  "kind": "webhook",
  "selection": {}
}

Consultar datasets de uma origem:

GET /v1/datasets?dataSourceId={id}

Use nomes de dataset estáveis. Eles aparecem em jobs, filtros de matches e imports.

3. Configurar fields canônicos

Fields definem quais valores do payload bruto serão extraídos para matching. Cada field tem uma key estável, usada por rule sets como left.amount, right.doc ou right.date.

POST /v1/datasets/{datasetId}/fields

[
  {
    "key": "external_id",
    "name": "ID externo",
    "type": "string",
    "sourcePath": "id_externo",
    "isIdentity": true
  },
  {
    "key": "amount",
    "name": "Valor",
    "type": "number",
    "sourcePath": "valor"
  },
  {
    "key": "date",
    "name": "Data",
    "type": "date",
    "sourcePath": "data"
  },
  {
    "key": "doc",
    "name": "Documento normalizado",
    "type": "string",
    "transform_expr": "$replace(row.documento, /[^0-9]/, '')"
  }
]

Regras:

  • key deve começar com letra e ter até 64 caracteres.
  • type pode ser string, number, date, boolean, cnpj ou cpf. Para cnpj e cpf, o valor é validado (dígitos verificadores) e normalizado para apenas dígitos; entradas inválidas viram null.
  • sourcePath usa notação por pontos dentro do payload original.
  • transform_expr é JSONata e recebe value e row no contexto.
  • Apenas um field por dataset deve ter isIdentity: true.
  • Para CSV/XLSX, sourcePath normalmente é o nome da coluna, a menos que o import use mapping.

4. Ingerir dados

Webhook: payload em tempo real

POST /hooks/{slug} é público e exige X-Webhook-Secret.

curl -sS https://<API_BASE>/hooks/transacoes-banco-x \
  -H "X-Webhook-Secret: um-segredo-com-no-minimo-16-chars" \
  -H "Content-Type: application/json" \
  -d '{
    "id_externo": "TX-2026-001",
    "valor": 1500.75,
    "data": "2026-05-06",
    "descricao": "Pagamento fornecedor ACME",
    "documento": "12.345.678/0001-99"
  }'

Resposta:

{ "ok": true }

Em cada entrega, o Nexus:

  1. valida Content-Type e X-Webhook-Secret;
  2. salva o primeiro sample em inbound_samples;
  3. cria o dataset se ele ainda não existir;
  4. extrai os fields configurados;
  5. calcula idempotência a partir dos valores extraídos;
  6. calcula blocking keys quando aplicável;
  7. enfileira matching automático para rule sets compatíveis.

Erros comuns:

HTTPcodeQuando acontece
400INVALID_JSONCorpo malformado.
401UNAUTHORIZEDSegredo ausente ou incorreto.
404NOT_FOUNDSlug inexistente.
409WINDOW_EXPIREDPrimeiro sample não chegou dentro da janela.
415UNSUPPORTED_MEDIA_TYPEContent-Type diferente de application/json.

Postgres: importar linhas selecionadas

Depois de testar e navegar a origem, enfileire a ingestão:

{
  "datasetName": "erp_transacoes",
  "selection": {
    "schema": "public",
    "table": "transactions",
    "columns": ["id", "amount", "date", "document"],
    "where": "date >= '2026-01-01'",
    "limit": 5000
  }
}

POST /v1/data-sources/{id}/ingest/postgres retorna 202:

{ "id": "ingest-job-uuid", "status": "queued" }

Observações:

  • selection.schema e selection.table são obrigatórios.
  • columns, where e limit são opcionais.
  • limit aceita até 5000 linhas por chamada.
  • O worker lê as linhas, aplica fields do dataset e dispara matching para records inseridos/atualizados.

Arquivos: upload e import

Para um data source file, envie o arquivo:

curl -sS -X POST https://<API_BASE>/v1/data-sources/<DATA_SOURCE_ID>/files \
  -H "x-api-key: $NEXUS_API_KEY" \
  -F "file=@./transacoes.xlsx"

CSV e XLSX ficam com status: "ready" após o upload e podem ser importados:

{
  "datasetName": "erp_transacoes",
  "mapping": {
    "external_id": "ID",
    "amount": "Valor",
    "date": "Data",
    "doc": "Documento"
  },
  "options": {
    "sheet": "Transacoes",
    "forceRematch": true
  }
}

POST /v1/data-sources/{id}/files/{fileId}/import retorna 202 com o import enfileirado.

Também é possível importar CSV/XLSX diretamente, sem associar a um data source de arquivo:

curl -sS -X POST https://<API_BASE>/v1/imports \
  -H "x-api-key: $NEXUS_API_KEY" \
  -F "datasetName=erp_transacoes" \
  -F "format=xlsx" \
  -F 'mapping={"amount":"Valor","date":"Data"}' \
  -F 'options={"sheet":1}' \
  -F "file=@./transacoes.xlsx"

Para Francesinha (.txt/.fra), o upload em /v1/data-sources/{id}/files dispara processamento automático e cria/atualiza o dataset de transações OpenFinance expandidas. Consulte arquivos e records gerados com:

GET /v1/data-sources/{id}/files
GET /v1/data-sources/{id}/files/{fileId}/records

OpenFinance e Openi: sincronização

Para data sources openfinance e openi, a ingestão principal é um sync:

curl -sS -X POST https://<API_BASE>/v1/data-sources/<DATA_SOURCE_ID>/sync \
  -H "x-api-key: $NEXUS_API_KEY"

Resposta:

{ "status": "queued" }

Antes do sync, use as rotas de browse para confirmar a seleção:

GET /v1/data-sources/openfinance/browse/accounts?itemId=...
GET /v1/data-sources/openfinance/browse/account-transactions?itemId=...&accountId=...
GET /v1/data-sources/openi/browse/invoices?companyId=...
GET /v1/data-sources/openi/browse/accounting-entries?companyId=...

5. Criar rule set e rodar matching

Um rule set sempre compara dois datasets distintos.

POST /v1/rule-sets

{
  "name": "Conciliação banco x ERP",
  "leftDatasetId": "9b6a2f30-...",
  "rightDatasetId": "0c1d2e3f-...",
  "engine": "jsonata",
  "jsonataExpr": "{ \"score\": (left.doc = right.doc and $abs(left.amount - right.amount) < 0.01) ? 1 : 0 }",
  "params": {
    "Tmatch": 0.85,
    "Tpossible": 0.6,
    "windowDays": 5,
    "amountTolerancePercent": 1.0,
    "blocking": {
      "enabled": true,
      "amountKey": "amount",
      "dateKey": "date",
      "amountTolerancePercent": 1.0,
      "dateToleranceDays": 5
    }
  }
}

Valide a expressão antes de salvar:

POST /v1/rule-sets/validate-jsonata
POST /v1/rule-sets/preview-jsonata

Execute uma conciliação completa:

POST /v1/rule-sets/{id}/run

Ou rode todos os rule sets aplicáveis a um dataset:

{
  "dataset": "erp_transacoes"
}

POST /v1/matching-jobs/run retorna 202 e permite acompanhar o progresso em GET /v1/matching-jobs/{id}.

Checklist de ativação

Antes de liberar tráfego real para um cliente novo:

  • Crie pelo menos dois data sources, um para cada lado da conciliação.
  • Valide credenciais e conectividade com /test ou uma carga piloto.
  • Crie datasets com nomes definitivos.
  • Configure fields canônicos equivalentes nos dois lados (amount, date, doc, identificadores externos).
  • Defina um field de identidade por dataset quando houver ID confiável.
  • Faça uma ingestão pequena e confira records extraídos.
  • Pré-visualize o JSONata com payloads reais.
  • Crie o rule set com blocking habilitado para datasets maiores.
  • Rode um matching manual e revise MATCH, POSSIBLE e NO_MATCH.
  • Configure webhooks de saída se o cliente precisar receber eventos em tempo real.

On this page