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 matchingConfigure 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
| Tipo | Quando usar | Como os records entram |
|---|---|---|
webhook | Seu sistema consegue enviar eventos JSON para o Nexus em tempo real. | POST /hooks/{slug} cria/atualiza records e dispara matching automático. |
postgres | Os dados estão em tabelas PostgreSQL acessíveis pelo Nexus. | O Nexus navega schemas/tabelas, enfileira uma ingestão e lê as linhas selecionadas. |
file | O cliente fornece CSV/XLSX recorrente ou arquivos Francesinha (.txt/.fra). | Upload multipart, depois import para dataset. Francesinha é processada automaticamente. |
openfinance | O cliente quer conciliar transações vindas do conector OpenFinance. | Sync busca contas/cartões/investimentos e transações; webhooks do provedor atualizam eventos novos. |
openi | O 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_plainsó é devolvido nesta resposta. Armazene o valor em um cofre.config.slugé opcional. Se omitido, o Nexus gera umwh-....- O primeiro payload precisa chegar em até 5 minutos. Se a janela expirar,
/hooks/{slug}retorna 409WINDOW_EXPIRED. PATCH /v1/data-sources/{id}pode alterar onameou oslug.
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/previewArquivos 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/testpara testar credenciais antes de criar, ou/v1/data-sources/{id}/testdepois.
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-reconciliation2. 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 emdatasetName; 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:
keydeve começar com letra e ter até 64 caracteres.typepode serstring,number,date,boolean,cnpjoucpf. Paracnpjecpf, o valor é validado (dígitos verificadores) e normalizado para apenas dígitos; entradas inválidas viramnull.sourcePathusa notação por pontos dentro do payload original.transform_expré JSONata e recebevalueerowno contexto.- Apenas um field por dataset deve ter
isIdentity: true. - Para CSV/XLSX,
sourcePathnormalmente é o nome da coluna, a menos que o import usemapping.
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:
- valida
Content-TypeeX-Webhook-Secret; - salva o primeiro sample em
inbound_samples; - cria o dataset se ele ainda não existir;
- extrai os fields configurados;
- calcula idempotência a partir dos valores extraídos;
- calcula blocking keys quando aplicável;
- enfileira matching automático para rule sets compatíveis.
Erros comuns:
| HTTP | code | Quando acontece |
|---|---|---|
| 400 | INVALID_JSON | Corpo malformado. |
| 401 | UNAUTHORIZED | Segredo ausente ou incorreto. |
| 404 | NOT_FOUND | Slug inexistente. |
| 409 | WINDOW_EXPIRED | Primeiro sample não chegou dentro da janela. |
| 415 | UNSUPPORTED_MEDIA_TYPE | Content-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.schemaeselection.tablesão obrigatórios.columns,whereelimitsão opcionais.limitaceita 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}/recordsOpenFinance 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-jsonataExecute uma conciliação completa:
POST /v1/rule-sets/{id}/runOu 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
/testou 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,POSSIBLEeNO_MATCH. - Configure webhooks de saída se o cliente precisar receber eventos em tempo real.

