Saltar para o conteúdo
BeryX

Developers

A qualidade dos teus dados, por API.

Lê scores, issues, contratos e vereditos do BeryX (antes chamado DataVault) a partir dos teus pipelines, do CI ou de um agente. REST, JSON, OpenAPI 3.1 — e tokens que só leem.

150 endpoints · versão 1.78.0 · atualizada a 13 de outubro de 2026

Começar

Da conta ao primeiro pedido em três passos.

  1. Cria um token

    Um admin do workspace cria-o em Definições → Tokens de API (planos Team e superiores). O valor dvk_… aparece uma única vez — guarda-o num cofre de segredos.

  2. Chama a API

    Envia o token no header Authorization: Bearer. Todas as respostas são JSON (exceto os exports .yml, .sql e .md).

  3. Automatiza

    Liga o veredito de um dataset ao teu CI, alimenta dashboards ou gera um cliente tipado a partir do contrato OpenAPI.

export DATAVAULT_TOKEN="dvk_…"

curl -s "https://api.praxis.lbostuff.tech/api/v1/datasets?limit=20" \
  -H "Authorization: Bearer $DATAVAULT_TOKEN"

Autenticação

Tokens de API: só leitura, por desenho.

Cada token pertence a um workspace e herda as suas permissões de leitura. Não abre a Consola, não altera dados e não vê credenciais das fontes.

  • Formato dvk_ seguido de 48 caracteres hexadecimais. Guardamos apenas o hash SHA-256 — se o perderes, cria outro.
  • Só GET, HEAD e OPTIONS, mais as poucas escritas marcadas na referência (gate RAG, disparo de scans, runs de orquestradores, data-diff e decisão de confiança em lote). Qualquer outro método devolve 403, mesmo que o endpoint exista.
  • Revogação imediata em Definições → Tokens de API; a última utilização fica visível para auditoria.
  • Criação e revogação ficam no registo de atividade do workspace.

Paginação

As listas aceitam limit e offset. O catálogo (GET /datasets) devolve o total no header X-Total-Count.

Header de autenticação

Authorization: Bearer dvk_3f9c…

Códigos de erro

401
Token em falta, inválido ou revogado.
402
A funcionalidade não está incluída no plano do workspace (ex.: dossiê do AI Act).
403
Método de escrita com um token, ou workspace suspenso.
404
O recurso não existe ou pertence a outro workspace.
422
Parâmetros inválidos — o corpo indica o campo e o motivo.

Todas as respostas trazem o header X-Request-ID. Os erros 4xx trazem detail (o motivo, legível), code (estável, para decidires no código; null se o erro não tiver um) e request_id, igual ao header. Cita o request_id ao suporte para encontrarmos o pedido nos logs.

HTTP/1.1 403 Forbidden
Content-Type: application/json
X-Request-ID: 7b0c1e4e-3f7a-4c1b-9a51-2d0f7f1e9c11

{
  "detail": "Tokens de API são read-only — usa uma sessão de utilizador para mutações.",
  "code": "token_read_only",
  "request_id": "7b0c1e4e-3f7a-4c1b-9a51-2d0f7f1e9c11"
}

Caso de uso

Um gate de qualidade no teu CI.

GET /datasets/{id}/verdict devolve pass, warn, fail ou unknown com as regras que falharam. Falha o deploy quando uma regra crítica falha ou o contrato de dados deixa de ser válido.

SDKs gerados do contrato

O openapi.json é gerado do código a cada release, por isso um cliente gerado nunca diverge da API. Os exemplos acima usam openapi-typescript e openapi-python-client; qualquer gerador OpenAPI 3.1 serve.

# .github/workflows/data-gate.yml → passo antes do deploy
verdict=$(curl -sf "https://api.praxis.lbostuff.tech/api/v1/datasets/$DATASET_ID/verdict" \
  -H "Authorization: Bearer $DATAVAULT_TOKEN" | jq -r .verdict)

echo "BeryX: $verdict"
[ "$verdict" != "fail" ] || exit 1

Estabilidade

O que acontece à tua integração quando a API muda.

O contrato é o que está neste portal. Uma versão minor só acrescenta; uma quebra só sai numa major, depois de uma depreciação anunciada. Resumo da política de versionamento — a versão em vigor é a 1.78.0.

  • 180 dias

    de aviso mínimo antes de uma operação depreciada deixar de responder

  • 30 dias

    de aviso antes de reduzirmos rate limits ou quotas

  • 2 minor

    do SDK Python suportadas ao mesmo tempo, com correções

  • O que é o contrato

    Tudo o que está neste portal: as operações de /api/v1 que um token de API consegue chamar, com os seus parâmetros, campos e códigos de estado. O resto da API (a app web, a gestão da conta e dos tokens, as áreas internas) não está coberto e pode mudar sem aviso.

  • Mudanças compatíveis (minor)

    Uma versão minor só acrescenta: operações, parâmetros opcionais, campos nas respostas, valores novos de enums e códigos novos. O teu cliente deve ignorar campos que não conhece e tratar valores de enum desconhecidos. Os code das razões e dos bloqueadores (decisão de confiança, readiness) são estáveis; os envelopes com schema_version (factos de confiança, feeds de BI) só mudam de schema_version numa quebra.

  • O que é uma quebra (major)

    Remover ou renomear uma operação, um parâmetro ou um campo; mudar o seu tipo ou formato; tornar obrigatório o que era opcional ou recusar um pedido que era aceite; mudar o significado de um campo, de um code ou de um estado HTTP. Uma quebra só sai de duas formas: numa versão de caminho nova (/api/v2), com /api/v1 sem mudanças, ou numa versão major anunciada no changelog depois de uma depreciação. O nosso CI compara cada alteração com o contrato publicado e recusa uma quebra que não esteja anunciada.

  • Depreciação

    Anunciada no changelog (tipo deprecated) pelo menos 180 dias antes do fim, com comunicação direta aos admins dos workspaces com tokens de API ativos. Durante a janela a operação continua a responder, com os headers Deprecation (RFC 9745 — desde quando), Sunset (RFC 8594 — quando deixa de responder) e Link com rel="deprecation" (a nota de migração). Exceção: uma correção de segurança pode encurtar a janela e fica no changelog com o tipo security.

  • SDK

    O SDK Python (beryx-sdk) tem versões próprias. Suportamos as duas minor mais recentes (N e N-1): recebem correções e acompanham a API. Versões mais antigas continuam a funcionar enquanto a API não tiver quebras, mas sem correções.

  • Rate limits e quotas

    Os limites de pedidos (por token e por IP) e as quotas do plano podem mudar; uma redução é anunciada com pelo menos 30 dias de antecedência, exceto medidas contra abuso. Os valores em vigor vêm nas respostas (X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset); acima do limite a API responde 429 com Retry-After e, acima de uma quota do plano, 402.

  • Reportar um problema

    Uma resposta que contradiga este contrato é um bug nosso. Escreve para suporte@praxis.lbostuff.tech com o método e o caminho, o estado HTTP, a hora (UTC), o X-Request-ID da resposta (nos erros vem também em request_id) e a resposta de GET /version (version, build_sha, api_version) — nunca o token. Vulnerabilidades: o contacto em /.well-known/security.txt.

Como sabes que algo vai ser removido

Uma operação depreciada continua a responder durante a janela, mas passa a trazer estes headers — e aparece no changelog abaixo com o tipo «Descontinuado». Vigia-os nos teus clientes: o CORS expõe-nos também no browser.

Ler a política completa

Exemplo de resposta de uma operação depreciada

HTTP/1.1 200 OK
Deprecation: @1790812800
Sunset: Thu, 01 Apr 2027 00:00:00 GMT
Link: <https://beryx.lbostuff.tech/developers#estabilidade>; rel="deprecation"; type="text/html"

Changelog da API

O que mudou no contrato.

Mudanças que quebram compatibilidade são anunciadas aqui antes de chegarem a produção. Novidades do produto em geral: ver o changelog do BeryX.

  1. v1.78.0

    • Novo

      access_role em GET /api/v1/datasets/{dataset_id}: o papel de quem pede nesse dataset, viewer, editor ou owner. É o mesmo papel com que a API decide os pedidos a esse dataset: as concessões das equipas nos domínios do dataset sobem o papel do workspace, e um domínio de acesso restrito só conta com uma concessão. Um token dvk_* só de leitura continua só de leitura, qualquer que seja o papel. Cartão #586.

  2. v1.77.0

    • Descontinuado

      O produto passa a chamar-se «BeryX». Os nomes com «DataVault» nos contratos já em produção continuam a valer até 31 de maio de 2027. Os webhooks e o export SIEM enviam X-BeryX-Event, X-BeryX-Delivery, X-BeryX-Timestamp e X-BeryX-Signature e, até essa data, também os X-DataVault-* com o mesmo valor; a assinatura é a mesma nos dois. As variáveis de ambiente do servidor, do servidor MCP, do SDK Python e do provider Terraform leem BERYX_<NOME> e DATAVAULT_<NOME>; com as duas definidas, ganha a nova, e a API e o worker avisam no arranque com os nomes antigos em uso. O servidor MCP chama-se beryx, e as configurações geradas em «Ligar o teu agente» usam beryx e BERYX_TOKEN. O GET /workspace/config descarrega beryx.yaml; o beryx config plan|apply e o scripts/workspace_config.py import sem caminho leem o beryx.yaml e, se não existir, o datavault.yaml. No export para dbt (o schema.yml e os testes singulares do rules.dbt-tests.zip), a regra vai em config.meta.beryx, e a suite GX leva a tabela e o unsupported em meta.beryx; o import e o casamento do run_results.json leem meta.beryx e meta.datavault, com a nova a ganhar. O User-Agent dos webhooks passa a BeryX-Webhooks/1 DataVault-Webhooks/1: um filtro que procure DataVault-Webhooks continua a aceitar as entregas. Não mudam: os nomes dos assets no Collibra, o namespace OpenLineage, o prefixo dvk_ dos tokens, os tipos de evento (datavault.alerts…) e os nomes dos ficheiros exportados (tests/datavault_*.sql e a suite <tabela>.datavault), para não duplicar os testes no teu repositório.

  3. v1.76.0

    • Segurança

      POST /synthetic-packs corre a avaliação utilidade × privacidade de GET /datasets/{dataset_id}/synthetic sobre as linhas de cada tabela antes de escrever o ficheiro. Com privacy_verdict = fail numa tabela, responde 409 e não envia ficheiro nenhum. O detail traz code = synthetic_privacy_fail, o message em pt-PT e, em tables, o name, o dataset_id, a key e os params de cada tabela recusada. O evaluation de cada tabela no manifesto deixa de vir null e traz o scorecard. Até aqui, o pack podia levar linhas que o export de um só dataset recusava. As chaves geradas de uma tabela referenciada também deixam de usar os valores que as colunas FK que apontam para ela não podem levar (amostras reais, extremos, PII real): um pack com esses valores no perfil muda de bytes. Cartão #561.

  4. v1.75.0

    • Novo

      language em GET /reports e GET /reports/{report_id}: a língua do texto de content_md (pt, en ou es). O LLM escreve na língua do workspace (workspace.default_locale) e o template offline escreve em pt; os relatórios anteriores vêm com null e estão em pt. Os títulos das secções continuam em português. Cartão #355.

  5. v1.74.0

    • Novo

      GET /api/v1/suggestions: o filtro category aceita enrichment, a categoria das propostas de enriquecimento (valores de fontes de referência com a fonte, a data e a confiança, aplicados por PR ou SQL depois de aprovados). Só nascem quando alguém pede uma proposta no dataset; a IA não as cria. Cartão #389.

  6. v1.73.0

    • Novo

      Webhooks de saída: code (código estável em inglês e snake_case, ex.: alerts_new, escalation_level, digest_weekly) e params (só números e identificadores) em todos os eventos do WebhookPayload, e title/body na língua do canal: o locale do config do canal, senão workspace.default_locale, senão pt-PT. Nos canais de email, cada destinatário recebe a mensagem na sua língua (locale da conta, senão a do workspace) e um endereço externo na do canal. Os códigos estão em docs/WEBHOOKS.md. Cartão #519.

    • Novo

      Erros na língua do pedido: o detail sai na língua da pessoa (locale da conta), senão na omissão do workspace, senão na do cabeçalho Accept-Language (pt, en ou es; de e fr recebem en), senão em pt-PT. Cada erro do catálogo traz o seu code estável, também os que até aqui tinham code null. Vale também para o 402/403 do plano, o 429 do rate limit e da fila de scans, o 413 do corpo e a message de um detail estruturado ({code, message}), cujo code não muda. Sem língua conhecida, o texto é o de antes. Cartão #519.

  7. v1.72.0

    • Novo

      GET /api/v1/datasets/{dataset_id}: o semantic de cada coluna do perfil ganha region. No tipo phone é o país do plano de numeração (ISO 3166-1 alfa-2), lido do país dos dados; nos outros tipos e em phone_pt (que é PT) vem a null. Cartão #516.

  8. v1.71.0

    • Novo

      Língua, região e fuso: locale (pt-PT, pt-BR, en-GB, en-US, es-ES, de-CH ou fr-CH) e timezone (IANA) em GET /auth/me, mais workspace.default_locale e workspace.timezone. PATCH /auth/me grava os da própria pessoa (só as chaves enviadas mudam; null volta à omissão do workspace) e GET/PUT /workspace/locale gere as omissões do workspace (admin). Cartão #518.

    • Novo

      Agendamentos com fuso: timezone (IANA) no corpo de PATCH /connections/{connection_id}/schedule e scan_timezone em GET /connections; timezone em POST/PATCH /report-schedules e na resposta. A hora (hour, scan_hour) lê-se nesse fuso e o próximo instante UTC calcula-se para cada ocorrência, por isso a hora local aguenta a mudança de hora. Os agendamentos existentes ficam em UTC e não mudam de hora; sem timezone, o PATCH mantém o fuso da conexão. Cartão #518.

  9. v1.70.0

    • Novo

      GET /api/v1/domains/suggestions: o domínio sugerido para os datasets sem domínio, pela maioria das ligações de linhagem a datasets já curados (pelo menos metade das ligações, sem empate). Cada sugestão traz os votos, o total de ligações, até 3 colunas via, os tipos de aresta, inferred_only e a signature da evidência; os empates vêm em ambiguous, com os candidatos. Admins veem todas; quem gere domínios só as desses domínios; os outros recebem 403. Um vizinho invisível conta no total e vem como «Dataset restrito». has_lineage diz se há alguma ligação de linhagem a um dataset visível, porque counts.with_lineage só conta os datasets sem domínio. Cartão #468.

    • Novo

      Qualidade dos metadados: o problema missing_domain ganha uma sugestão com channel: "lineage" quando há datasets sem domínio com sugestão pela linhagem («Juntar pela linhagem — N com sugestão», com link para /datasets?vista=dominios e endpoint GET /api/v1/domains/suggestions). Valor novo no enum channel de MetadataSuggestionOut. Cartão #468.

  10. v1.69.0

    • Novo

      País dos dados (ISO 3166-1 alfa-2): data_country em GET /connections e GET /connections/{connection_id} (o da fonte; null = o do workspace), data_country em GET /datasets e GET /datasets/{dataset_id} (o próprio do dataset; null = herdado) e country no detalhe do dataset, com o país effective que os scans usam (dataset → conexão → workspace) e a source de onde vem. GET /datasets/{dataset_id}/data-country dá o mesmo objeto. O workspace tem PT por omissão, por isso nada muda até alguém escolher outro país; noutro país, os telefones de 9 dígitos sem indicativo e os códigos postais deixam de ser lidos como portugueses. Cartão #513.

  11. v1.68.0

    • Novo

      Schema de resposta em 30 operações que devolviam um objeto sem schema. Os campos são os que já vinham e o JSON não muda. São o veredito (GET /datasets/{dataset_id}/verdict e GET /domains/{domain_id}/verdict), a decisão e os factos de confiança (GET /datasets/{dataset_id}/trust-decision, POST /trust-decisions, GET /datasets/{dataset_id}/trust-facts e GET /domains/{domain_id}/trust-facts), a prontidão (GET /datasets/{dataset_id}/ai-readiness e GET /domains/{domain_id}/readiness), a pesquisa e a linhagem (GET /datasets/find, GET /datasets/{dataset_id}/lineage, …/lineage/traverse, …/lineage/impact e …/lineage/path), o contexto (GET /datasets/{dataset_id}/context), o data-diff (POST /datasets/{dataset_id}/diff/{other_id}), os contratos (GET /datasets/{dataset_id}/contract/versions, …/contract/versions/{number}, …/contract/diff, …/contract/proposals e …/contract/proposals/{proposal_id}), a política de dados (GET /workspace/data-policy e GET /domains/{domain_id}/data-policy), o AI Act (GET /compliance/ai-systems, …/ai-systems/{system_id} e …/art10), os orquestradores (POST /integrations/dbt/run-results, GET /orchestrator-runs e POST /orchestrator-runs) e as leituras da extensão do VS Code (GET /ide/resolve e GET /ide/datasets/{dataset_id}/columns). Um cliente gerado a partir deste spec passa a ter estes campos, e a nossa verificação de quebras passa a ver dentro destas respostas. Cartão #455.

  12. v1.67.0

    • Novo

      GET /datasets/{dataset_id}/rules/export?format=dbt|sodacl|gx: as regras ativas do dataset como ficheiro para o teu repositório, em testes dbt (schema.yml, o mesmo de GET /datasets/{id}/rules.dbt.yml, que continua), checks SodaCL (missing_count, duplicate_count, invalid_count com valid regex/valid min/valid max, freshness, row_count) ou uma suite do Great Expectations 1.x (JSON). No SodaCL e no GX só sai o que o POST /rules/import lê de volta como a mesma regra; o que fica de fora (regras de streams, validade por dígito de controlo, regras SQL, tolerâncias acima de zero…) vem com o motivo no cabeçalho do ficheiro (meta.datavault.unsupported no GX) e conta-se nos headers X-Rules-Exported, X-Rules-Unsupported e X-Rules-Unsupported-Types. GET /rules/export?format=sodacl: as regras dos datasets que quem pede vê, num só ficheiro SodaCL. O POST /rules/import passa a ler invalid_count com validade e duplicate_count de várias colunas no SodaCL, expect_compound_columns_to_be_unique no GX e frescura em minutos (30m), e o dedupe vê como a mesma regra a tolerância a zero e a ausente, columns: [x] e column: x, 12.0 e 12: reimportar o ficheiro não duplica regras. Sem LLM e sem tocar na fonte. Cartão #403.

  13. v1.66.0

    • Novo

      Problemas «esperados»: cada issue de GET /issues e de GET /datasets/{id} ganha resolution_reason: expected quando foi ignorado como esperado (uma migração, um fecho de mês), null nos restantes. No GET /issues/sla-report, um issue esperado conta nos opened e no MTTA, mas fica fora dos resolved, do MTTR e do in_scope/breached. Cartão #401.

  14. v1.65.0

    • Segurança

      O 422 da validação deixa de devolver o valor recebido: cada item de detail traz type, loc e msg, e o ctx só com os limites da regra (gt, ge, lt, le, multiple_of, min_length, max_length, max_digits, decimal_places). O input de um campo em falta era o corpo inteiro do pedido, e no POST /auth/login e no POST /auth/register isso incluía a password. Os campos input e ctx continuam no schema ValidationItem até à próxima major, mas o input já não vem. Cartão #450.

  15. v1.64.0

    • Novo

      GET /incidents e GET /incidents/{incident_id}: raio de impacto do incidente. impact_scope é column quando os problemas da raiz são de uma coluna (impact_columns) e há linhagem coluna-a-coluna (lida do SQL das views) a sair dela: a impact_tree só leva os datasets que usam essas colunas e os de impacto possível, onde falta o mapa de colunas. É table ao nível da tabela, como antes, com impact_note: no_column_lineage quando os problemas eram de uma coluna sem esse mapa, e none quando nada a jusante é afetado. Cada nó da árvore ganha impact (column = certo, table = possível) e via_columns; o incidente ganha downstream_count, downstream_column_count e exposures_count. Num dataset restrito, via_columns vem vazio. Cartão #402.

  16. v1.63.0

    • Novo

      GET /rules/{rule_id}/failing-rows.sql?dialect=&limit=: a query que lista as linhas que falham a regra, em texto, para correres no teu warehouse (o DataVault não a executa nem guarda linhas). Dialeto por omissão o da fonte do dataset (X-DataVault-Dialect), ou postgres, mysql, mssql, bigquery, snowflake, databricks e sqlite; nomes sempre citados e LIMIT/TOP do dialeto (limit de 1 a 1000, omissão 100). Uma regra sem tradução por linha (row_count_min, regras de streams, lista acima de 500 valores…) responde 204 com o motivo em X-DataVault-Reason. Um token dvk_* pode chamá-la e o pedido fica no trilho de auditoria como leitura (failing_rows_sql_read). Cartão #400.

  17. v1.62.0

    • Novo

      SLA de resolução por severidade: GET /issues/sla-report?period=AAAA-MM&group_by=domain|team|severity devolve, por grupo e no total, os issues criados, fechados (resolvidos ou ignorados) e por resolver no fim do mês, quantos passaram o alvo (breached, sobre in_scope), o MTTA e o MTTR (mediana e p90, em horas de relógio do SLA: por resolver e sem os adiamentos) e o ageing das abertas (lt_1d, d1_3, d3_7, d7_30, gt_30d). Só conta os datasets que quem pede vê. Cada issue de GET /issues ganha sla_breached_at (quando passou o alvo da sua severidade; null dentro do SLA ou sem alvo) e GET /issues aceita sla=breached. Cartão #396.

  18. v1.61.0

    • Novo

      POST /datasets/{dataset_id}/validate: valida até 5 000 registos (corpo até 2 MB; acima, 413) contra as regras ativas do dataset e devolve, por registo, se passou e que regras falharam, com um code estável (invalid_check_digit, pattern_mismatch, not_in_reference…) e os params da regra; por regra, quantos registos passaram, falharam ou não se aplicam, com a tolerância da regra; e o verdict do lote (pass, warn, fail ou unknown). As regras do dataset inteiro (unique, freshness, row_count_min…) ficam com not_applicable_code. Nada é guardado. Um token dvk_* pode chamá-la, com rate limit próprio por token (429 com Retry-After). Cartão #397.

  19. v1.60.0

    • Alterado

      Os erros 4xx passam a ter sempre o mesmo corpo (schema ErrorResponse; no 422 e no 402, ValidationErrorResponse e PlanLimitErrorResponse, com os mesmos campos): detail como antes, code (código estável quando existe — auth_required, token_invalid, token_read_only, workspace_suspended, plan_limit, org_quota, validation_error, rate_limited, scan_queue_full, payload_too_large — senão null) e request_id, o mesmo valor do header X-Request-ID. Os campos próprios de cada erro (plan e limit no 402, retry_after no 429) mantêm-se. Cartão #361.

    • Alterado

      O OpenAPI documenta os erros: 401 e 403 em todas as operações autenticadas, 404 nas que têm um id no caminho, 402 nas que dependem do plano (com plan e limit no schema), o 422 com o mesmo envelope (cada item com os campos de antes: loc, msg, type, input e ctx) e o header X-Request-ID em todas as respostas. Os schemas principais (datasets, issues, scans, gate RAG, decisão de confiança) e as respostas do veredito, dos factos de confiança, da readiness, das versões de contrato, da reconciliação e da resolução no IDE trazem exemplos. Cartão #361.

  20. v1.59.0

    • Novo

      Campos confidence_band (high, low, ou exact quando as linhas do cluster são iguais nas colunas comparadas) e reference_precision nos clusters de GET /duplicates: a confidence é a semelhança média dos pares, não uma probabilidade; a banda e a precisão de referência (fração de clusters com essa semelhança que eram duplicados reais) vêm de um benchmark sintético português, não dos dados do cliente. A confidence de um cluster fuzzy novo fica abaixo de 1, que passa a ser só dos exatos. Cartão #352.

  21. v1.58.0

    • Novo

      Campo kind nos datasets (table, view, materialized_view, external ou unknown): o tipo do objeto na fonte. Uma view ou external perfila em basic sobre as primeiras linhas, salvo profundidade própria standard ou deep do dataset. Cartão #347.

    • Novo

      Campos primary_key, partition e clustering em cada coluna do detalhe de um dataset: o que a fonte declara sobre ela. Cartão #347.

    • Novo

      Campo cost_guarded nos datasets: true quando os scans o perfilam em basic sobre as primeiras linhas e sem contar valores distintos (kind view ou external, sem profundidade própria standard ou deep). Cartão #347.

    • Alterado

      key_columns passa a opcional no data-diff (POST /datasets/{id}/diff/{other}): sem ele, a chave é a chave primária declarada na base, se o candidato tiver as mesmas colunas; senão, 422 como antes. O relatório traz key_source (request ou primary_key). Cartão #347.

  22. v1.57.0

    • Alterado

      A dimensão consistencia do score (score_history[].dimensions, GET /datasets/{id}) passa a descontar os issues schema_drift e anomaly abertos ou reconhecidos do dataset, e não só o drift do próprio scan: 15 pontos por aviso e 30 por crítico, × (1 − idade/K), em que a idade são os scans desde a última deteção e K = DATAVAULT_CONSISTENCY_DECAY_SCANS (5). Um issue resolvido ou ignorado deixa de descontar no scan seguinte. O drift estrutural (colunas removidas, tipo alterado) continua a contar só no scan que o deteta. Os scores já gravados não mudam. Cartão #351.

    • Novo

      Valor consistency_issue no kind dos drivers de GET /datasets/{id}/score/explain: um issue aberto cujo desconto na consistência mudou, com issue_id e params change (opened, decaying, detected_again, gone), age_before, age_after, points_before, points_after e decay_scans. Nota nova consistency_model_changed quando um dos scores é anterior a esta versão. Cartão #351.

  23. v1.56.0

    • Novo

      Números calculados sobre amostras dizem-no com os mesmos campos: estimated, sample_size e o intervalo de confiança a 95% (ci95, ou <campo>_ci95 quando o objeto tem vários números). dimensions_meta.unicidade.ci95 no score; semantic.estimated e semantic.sample_size no perfil das colunas; sample_matches e sample_size nas colunas do mapa de PII. Cartão #350.

  24. v1.55.0

    • Novo

      Valor bi_refresh no type dos issues: refresh falhado (subtype failed) ou atrasado (delayed) de um dataset BI do Power BI, do Tableau ou do Looker, preso ao dataset de que ele depende; impact_json traz bi_dataset_id, bi_dataset_name e os dashboards afetados. Cartão #271.

  25. v1.54.0

    • Novo

      Paginação uniforme: GET /issues, GET /scans, GET /signals e GET /knowledge passam a devolver o total filtrado no header X-Total-Count, como já faziam GET /datasets, /rules, /suggestions e /reports. GET /scans, GET /signals e GET /orchestrator-runs aceitam offset. Em todas as listagens, limit vai de 1 a 500 (GET /scans, GET /knowledge e GET /orchestrator-runs paravam nos 200), offset é ≥ 0 e um limit acima do teto dá 422. O corpo continua a ser uma lista e o limit por omissão de cada listagem não muda. Na pesquisa híbrida de GET /knowledge, o total é o tamanho da lista fundida sobre a qual corre a paginação. Cartão #333.

  26. v1.53.0

    • Novo

      Feed BI chargeback em GET /bi/chargeback: uso e custo do workspace do token por mês, com uma linha por workspace, por domínio e por equipa (month, dimension, workspace_id, workspace_name, entity_id, entity_name, scans, datasets, reports, llm_tokens, llm_tokens_byok, llm_cost_usd, llm_cost_eur, profile_bytes). entity_id vazio numa linha de domínio ou de equipa = sem domínio ou sem equipa. Um dataset em dois domínios conta metade em cada; a parte de um domínio vai para as equipas owner (sem owner, para as editor). Por omissão cobre os meses dos últimos 365 dias; domain_id deixa só as linhas desse domínio. Cartão #259.

  27. v1.52.0

    • Novo

      Equipas como responsáveis: cada issue de GET /issues ganha assignee_team_id e assignee_team_name (a equipa responsável, além da pessoa; null sem equipa). GET /issues e GET /issues/board aceitam assignee_team — o id de uma equipa, mine (as equipas de quem pede) ou none (sem equipa). GET /issues/board ganha team_cells, as contagens estado × equipa (status, team_id, team_name, count; team_id null = sem equipa). Atribuir a equipa é da UI e só aceita uma equipa que leia o dataset do issue. Cartão #240.

  28. v1.51.0

    • Novo

      Montra pública de um data product, com o mesmo modelo do badge do dataset (token opaco, fora do portal, sem conta): GET /public/badge/domains/{token}.svg devolve o badge estilo shields.io — à esquerda o cumprimento do SLA no mês («SLA 99,2 %») ou, sem SLA declarado, o score; à direita a readiness para BI, verde (ready), âmbar (ready_with_warnings) ou vermelho (not_ready) — com ETag e Cache-Control: public, max-age=3600. GET /public/domains/{token} devolve o JSON da página /p/dominios/{token}: nome, descrição, nome do owner, versão e estado, score, SLA declarado e cumprimento do mês, readiness por caso de uso (rag, ml, agente, bi, com estado e códigos dos bloqueadores e avisos) e, por dataset, nome, veredito, score e os links públicos só se o dataset também estiver partilhado, mais generated_at; com ETag e Cache-Control: no-cache. Nunca emails, ids internos, colunas ou amostras. Os dois partilham o rate limit por IP do badge do dataset; um token desconhecido ou revogado dá 404. A gestão (GET, PUT e DELETE /domains/{domain_id}/public-share e POST …/public-share/rotate) é da UI: ver é de quem lê o domínio; ativar, rodar e revogar, de um admin, do owner do domínio ou de uma equipa owner. Cartão #180.

  29. v1.50.0

    • Novo

      Ensaio da remediação: cada item de GET /suggestions ganha rehearsal, o último ensaio só-leitura do passo de diagnóstico da sugestão (null se nunca foi ensaiada). Traz version, status (queued, ok, blocked, timeout ou error), affected_rows (linhas que o passo 1 devolve, contadas na fonte), total_rows (linhas do dataset no último scan), pct, requested_at, ran_at, duration_ms e actor (o email do admin que o pediu). Quando não contou, reason traz code (no_diagnosis, aggregate, limit, not_select, forbidden, function_not_allowed, unknown_table, timeout, source_error, blackout…), params e message em pt-PT, de recurso. Com status = ok, o impact da sugestão passa a ter estimated_rows igual às linhas contadas, estimated_rows_sample com a estimativa anterior e rows_source = rehearsal. Só contagens: nunca valores nem o SQL. Cartão #178.

  30. v1.49.0

    • Novo

      Avaliação dos dados sintéticos: GET /datasets/{dataset_id}/synthetic/evaluation?rows=&seed= devolve o scorecard das mesmas linhas que GET /synthetic enviaria com esse par. utility_score (0–100) mede a fidelidade ao perfil (nulos, quantis p05–p95 normalizados pelo IQR, distância de variação total aos histogramas e às quotas categóricas, correlações dos pares), com utility_components e utility_weights. privacy_verdict é fail com sample_leak, extreme_leak ou pii_leak, warn com k_min abaixo de k_threshold (5), contado só sobre os quase-identificadores com valores do domínio real (numéricos, temporais ou categóricos), e pass no resto. O motivo chega como key (leaks em fail, k_below em warn, null em pass) e params (sample_columns, extreme_columns e pii_columns em leaks; k_min, k_threshold e qi_columns em k_below), com que a UI compõe o texto, e reason é o mesmo texto em pt-PT, de recurso. Só taxas, deltas, contagens e nomes de colunas. Cartão #174.

    • Alterado

      GET /datasets/{dataset_id}/synthetic corre a avaliação antes de enviar: com privacy_verdict = fail responde 409 e não envia nenhuma linha (CSV ou JSON); o detail traz code = synthetic_privacy_fail, a key e os params do motivo e o message em pt-PT. Em format=json, o manifest traz o scorecard em manifest.evaluation. O pack multi-tabela (POST /synthetic-packs) ainda não corre esta avaliação: o evaluation de cada tabela no manifesto do pack continua null. Cartão #174.

  31. v1.48.0

    • Novo

      Pack de dados sintéticos multi-tabela para dev/test e fixtures de CI: POST /synthetic-packs (tag synthetic, permitido a tokens) com exatamente um de connection_id, domain_id ou dataset_ids (até max_tables, no máximo 20), rows_per_table (até 20 000 por omissão), seed e format: zip (um CSV por tabela, schema.sql com chaves e FKs e manifest.json com estratégias, FKs, avisos, seed e o aviso «dados sintéticos — não contém dados reais») ou sqlite (as mesmas tabelas e o manifesto na tabela _datavault_manifest). As colunas ligadas pela linhagem (cliente_id → clientes) só levam chaves que existem na tabela de origem, com a taxa de nulos do perfil; num ciclo da linhagem, a FK que o fecha sai, com aviso. A mesma chamada sobre os mesmos perfis dá os mesmos bytes. Síncrono e com orçamento de tempo (30 s por omissão): excedido, 422 sem ficheiro. Um campo desconhecido no corpo dá 422. Cada workspace tem um limite de pedidos (20 em 10 minutos por omissão), partilhado por membros e tokens: acima, 429 com Retry-After. Um dataset ou domínio invisível para quem pede é «não encontrado». Cartão #175.

  32. v1.47.0

    • Novo

      Os bloqueadores e avisos do trust score (blockers[] e warnings[] de GET /datasets/{dataset_id}/trust e do trust de GET /datasets/{dataset_id}) ganham params: os números com que o texto se compõe, por key — critical_issue traz count; schema_change_unacknowledged traz count, grace_days e oldest_days; unused_dataset vem sem params. O message continua em pt-PT. Cartão #476.

  33. v1.46.0

    • Novo

      Travessia do grafo de linhagem, determinística e sem LLM (as mesmas consultas das tools get_lineage, impact_of, path_between e find_datasets do assistente e do servidor MCP): GET /datasets/{dataset_id}/lineage/traverse?direction=&hops= (upstream e/ou downstream até 3 saltos, com o caminho «A → B → C», a origem de cada aresta em kinds, o mapa de colunas e os exposures a jusante), GET /datasets/{dataset_id}/lineage/impact?column= (datasets, exposures e destinos a jusante e, com a coluna, as colunas que derivam dela), GET /datasets/{dataset_id}/lineage/path?target_id= (caminho mais curto até 6 saltos, no sentido do fluxo ou no inverso) e GET /datasets/find (filtros compostos: query, layer, domain, has_pii, min_score, usage_class). Até 40 datasets e 60 arestas (truncated), só nomes: nunca o owner, o email nem o URL de um exposure. Um dataset invisível para quem pede é «Dataset restrito». Cartão #173.

  34. v1.45.0

    • Novo

      Versões do data product: GET /domains/{domain_id}/versions lista as versões publicadas (a mais recente primeiro) com version (MAJOR.MINOR), bump (major quebra o consumidor: um dataset saiu, uma coluna do contrato ativo desapareceu ou o SLA enfraqueceu; minor é compatível), change_summary e contagens. GET /domains/{domain_id}/versions/{from_version}/diff/{to_version} devolve as mudanças entre duas versões no formato do diff de contratos, cada uma com impact; from_version=latest e to_version=current comparam o estado atual com a última versão e trazem next_version; de uma versão mais antiga até current, next_version é null. latest no destino ou current na origem dão 422. Cartão #168.

    • Novo

      GET /domains e GET /domains/{domain_id} ganham status (draft | published | deprecated), version e published_at (null até à 1.ª publicação). Os domínios que já existiam estão published na 1.0. Cartão #168.

    • Novo

      GET /domains/{domain_id}/readiness tem dois códigos novos: o bloqueador deprecated (data product descontinuado) e o aviso draft (em rascunho). Cartão #168.

  35. v1.44.0

    • Novo

      GET /knowledge/graph passa a ser o grafo do património: nós domain, exposure, metric e term (ao lado de connection, dataset, rule, issue, signal e kb_entry) e arestas feeds (linhagem upstream → downstream, com lineage_kind: inferred, declared, parsed, dbt ou openlineage; num par com várias, ganha a que não é inferred), member_of (dataset → domínio), consumed_by (dataset → exposure dbt), measures (métrica dbt → dataset de origem, resolvido pelo nome; um nome ambíguo fica sem aresta) e means (termo não depreciado do glossário → dataset, pelas ligações aprovadas, com as colunas em column). stats.by_edge_kind conta as arestas por tipo. No corte a 1500 nós ficam primeiro as fontes, os domínios e os datasets. Cartão #172.

    • Novo

      GET /knowledge/graph aceita focus=dataset:<id>: devolve só a vizinhança desse dataset a hops saltos (1 a 3; 2 por omissão), com teto de 400 nós — ficam primeiro os mais próximos. kinds (tipos de nó separados por vírgulas) limita os tipos de nó; o do foco entra sempre. hops fora de 1–3, kinds com um tipo desconhecido ou um focus que não seja dataset:<id> dão 422; um dataset que não é do workspace dá 404. Cartão #172.

  36. v1.43.0

    • Novo

      POST /trust/consumptions: um agente, aplicação, pipeline ou notebook regista os datasets que consumiu (até 50), a finalidade e a decisão de confiança que viu (decision_seen; omitida, fica a decisão atual da Trust API e o seu as_of em trust_as_of). O consumidor nasce no primeiro registo e é identificado por name + kind. Com consumer.run_ref, repetir o registo do mesmo run não cria consumos novos (replayed). Só ids e rótulos: campos desconhecidos dão 422. O consumer.name só aceita letras (de qualquer língua), algarismos, espaços e _ . : / -; marcação de Slack, Teams ou markdown dá 422. Responde 201; 404 se um dataset não é do workspace; 429 com Retry-After acima do limite por workspace. É uma escrita permitida aos tokens dvk_*. Um consumo em untrusted gera o evento consumer_untrusted_read e um aviso aos canais, sem abrir problema; os canais recebem no máximo um aviso por hora por consumidor e dataset. Cartão #166.

    • Novo

      GET /consumers e GET /datasets/{dataset_id}/consumers: os consumidores registados, com consumptions_7d, consumptions_30d, datasets_30d, decisions_7d (consumos dos últimos 7 dias por decisão), last_decision, last_purpose e last_consumed_at. No dataset, as contagens e a última decisão são as desse dataset. GET /consumers traz X-Total-Count. Cartão #166.

    • Novo

      Os consumidores afetados (exposures) de GET /incidents, GET /incidents/{incident_id} e GET /issues/{issue_id}/impact ganham node: exposure (dbt, como até aqui) ou consumer (consumidor registado com consumos nos últimos 30 dias). Um consumer traz framework, consumptions_7d, last_decision e last_consumed_at do dataset por onde o impacto chega, e o type é o tipo do consumidor (agent, application, pipeline, notebook). Cartão #166.

  37. v1.42.0

    • Novo

      Limiares afinados pelo feedback: GET /datasets/{dataset_id}/tuning devolve, por métrica×coluna (subtype dos issues de anomalia), o degrau em vigor (threshold, na escala clássica do |z|: 3,5 é o limiar calibrado sem afinação), se está silenciada, quantas vezes foi ignorada e resolvida, e o que o próximo «ignorar» faz (next_on_ignore). Traz também os reajustes de regras à espera de aprovação (retunes). Cartão #157.

    • Novo

      O cartão de explicação de uma anomalia (GET /issues/{issue_id}/explanation) traz tuned_threshold (o degrau afinado pelo feedback que entrou no z_threshold) e tuned_threshold_label («limiar afinado por feedback: 5,0»). Vêm null quando a métrica não tem afinação. Cartão #157.

  38. v1.41.0

    • Novo

      GET /domains/{domain_id}/consumers: quem depende do data product. Utilizadores e consumidores externos registados à mão (source=manual) e os sistemas de IA e exposures dbt que usam os datasets do domínio (source=derived). by_kind conta os quatro tipos (user, ai_system, dbt_exposure, external), total soma-os e summary é a frase de impacto («3 sistemas de IA e 2 dashboards dependem deste produto»), null sem consumidores. Um consumidor com channel_id recebe o aviso de uma violação crítica do SLA. Cartão #165.

    • Novo

      GET /domains/{domain_id}/readiness ganha consumers: {total, by_kind} com os quatro tipos de consumidor sempre presentes. É informativo e não muda o status. Cartão #165.

  39. v1.40.0

    • Novo

      GET /rules: cada regra traz last_result, o último resultado num scan, com status (passed, failed ou not_evaluated), scan_id, evaluated_at, observed e threshold. Antes do primeiro scan com a regra vem a null. Uma regra not_evaluated correu mas não se conseguiu verificar: não abre issue nem conta no score, e reason diz porquê (por exemplo, uma regra referential cuja referência, noutra ligação, passa das 200 000 chaves). Se a razão nomear um dataset de referência que quem pede não vê, sai uma frase sem o nome. Cartão #164.

    • Novo

      Regra referential (integridade referencial entre datasets): rule_type em GET /rules passa a poder ser referential, com params column, ref_dataset_id, ref_column e max_orphan_pct. Em GET /datasets/{dataset_id}/rules.dbt.yml sai como teste relationships (to: ref('<tabela>'), field), e em GET /datasets/{dataset_id}/contract e GET /domains/{domain_id}/contract como check invalidValues com arguments.references (<schema.tabela>.<coluna>). Uma referência a um dataset que quem pede não vê não dá nome nestes exports: sai do contrato, e no rules.dbt.yml fica só uma nota em comentário.

  40. v1.39.0

    • Novo

      GET /tickets/integrations/{integration_id}/targets: onde uma integração de tickets pode criar tickets, lido agora do fornecedor. No Jira, os projetos (key é a chave do projeto) com os tipos de issue de cada um (issue_types, sem subtarefas); no Linear, as equipas (key é o id da equipa e issue_types vem vazio). Até 100 destinos. default_project e default_issue_type são o destino configurado na integração (default_issue_type é null no Linear). Só lê: GET no Jira, *query* GraphQL no Linear. 404 se a integração não for deste workspace, 402 se o plano não incluir os webhooks de alertas (a mesma condição de POST /tickets), 502 se o fornecedor falhar ou se a proteção anti-SSRF recusar o endereço. Cartão #375.

  41. v1.38.0

    • Novo

      Marcação do conteúdo gerado por IA (Regulamento da IA, art. 50.º, n.º 2): ai_generated, ai_model e generated_at nos relatórios e diagnósticos RCA (GET /reports, GET /reports/{report_id}) e nas sugestões (GET /suggestions, suggestions em GET /datasets/{dataset_id}). ai_generated é false no texto do modo offline, que é determinístico; aí ai_model e generated_at vêm a null. Nas sugestões IA anteriores a esta versão, e nas que o assistente propõe, ai_model vem a null. O modelo nunca traz ARNs nem ids de conta ou de projeto: um id de recurso cloud sai como a família do modelo (por exemplo, claude-sonnet-5) ou como undisclosed. Cartão #511.

    • Novo

      GET /datasets/{dataset_id}/readme: ai_generated e ai_model do rascunho (a data é o generated_at que já existia) e published_ai_generated e published_ai_model da versão publicada, que continua marcada depois de aprovada. O export GET /datasets/{dataset_id}/readme.md de um README gerado por IA começa com um front matter YAML (ai-generated, ai-model, ai-generated-at).

    • Novo

      Exports GET /reports/{report_id}/export e GET /reports/{report_id}/export.pdf (e a partilha pública): <meta name="ai-generated"> (true ou false) e, quando houve IA, ai-model e ai-generated-at, mais o rótulo visível «Gerado por IA (modelo, data)» no cabeçalho. No PDF os mesmos valores vão para os metadados do documento, com os nomes sem hífens (aigenerated, aimodel, aigeneratedat).

  42. v1.37.0

    • Novo

      GET /datasets/{dataset_id}/parsing: campos compostos do último perfil (moradas, nomes completos, telefones com indicativo, NIF e nome na mesma coluna, datas em texto livre e montantes com moeda). Cada coluna traz o tipo (kind), o locale (pt, es ou en), a taxa de sucesso na amostra (success_rate, parsed/samples), a cobertura de cada coluna derivada (components), as máscaras dos valores que não se decompõem (failing_masks, dígito → 9, letra → A, sem valores) e a assinatura da sugestão com o SQL e o PySpark só de leitura (suggestion_signature, parse_standardize:<coluna>). Sem perfil, profiled é false.

  43. v1.36.0

    • Novo

      GET /tickets?entity_type=…&entity_id=…: os tickets externos (Jira, Linear ou outra ferramenta) ligados a um issue, a um incidente (inc-…), a uma sugestão, a uma proposta de contrato ou à classificação de uma coluna, com provider, external_key, url e status (open, in_progress, done ou unknown). O estado ainda não é sincronizado com a ferramenta: um ticket criado pelo DataVault nasce open; um ligado à mão, ou anterior a esta versão, fica unknown. Cartão #374.

    • Novo

      tickets em cada issue (GET /issues, e open_issues em GET /datasets/{dataset_id}): um issue passa a poder ter vários tickets externos, do mais antigo para o mais recente.

    • Novo

      Valores novos nos rastos: field = ticket (ticket criado) ou ticket_link (ticket existente ligado) em GET /issues/{issue_id}/events, com a chave do ticket em to_value; to_status = ticket em GET /suggestions/{suggestion_id}/events (o estado da sugestão não muda). Trata um valor que não conheças como «outro».

    • Descontinuado

      external_ticket_url nos issues — usa tickets. Continua a responder, com o URL do primeiro ticket ligado, e só sai numa versão major, não antes de 2027-04-05.

  44. v1.35.0

    • Novo

      POST /integrations/dbt/run-results: o dbt test/dbt build corrido no pipeline do cliente devolve os resultados ao DataVault. Corpo {run_results, manifest, connection_id?} com o target/run_results.json (schema v4 a v6) e o target/manifest.json do mesmo projeto. Cada teste casa com o dataset (schema + alias) e com a regra — pelo rule_id em config.meta.datavault, senão pela coluna e tipo de teste. Com regra, o resultado conta para GET /datasets/{dataset_id}/verdict (uma regra crítica que falha no dbt dá fail; o envio seguinte com pass limpa-o); sem regra equivalente (testes singulares, relationships), abre ou resolve um issue rule_violation com subtype dbt_test (fail/error → critical, warn → warning). O mesmo invocation_id reenviado não grava nada outra vez (status duplicate). Com domínios restritos, só casa com os datasets em que quem envia pode escrever; os outros ficam como no_dataset, sem dataset_id nem rule_id. Só metadados de execução: schema fechado — chaves desconhecidas, campos com linhas (failed_rows, rows…) ou um failures que não seja uma contagem dão 422. Aceita tokens de API. Cartão #394.

    • Novo

      dbt_core em OrchestratorSource (filtro source de GET /orchestrator-runs): cada dbt test recebido fica como um run com o invocation_id como external_run_id. Cartão #394.

    • Alterado

      GET /datasets/{dataset_id}/verdict: cada entrada de failed ganha engine — datavault (scan do DataVault) ou dbt (dbt test do cliente; observed é então a contagem de linhas falhadas). O veredito é o do último scan do DataVault, com o resultado dbt mais recente de cada regra por cima. Cartão #394.

  45. v1.34.0

    • Novo

      Veredito do data product: GET /domains/{domain_id}/verdict agrega os vereditos dos datasets do domínio para o gate de CI — fail se algum falha, warn se algum avisa, unknown se nenhum tem veredito (domínio sem datasets ou sem scans) e pass nos outros casos. Devolve domain_id, domain_name, verdict, with_policy, counts (quantos datasets em pass, warn, fail e unknown) e datasets[], ordenados por nome: cada um é o GET /datasets/{dataset_id}/verdict desse dataset, mais dataset_id e dataset_name. with_policy (omissão true) conta as violações da política de dados, como o veredito por dataset; com false, só a qualidade. Cartão #148.

    • Novo

      Contratos ODCS do data product: GET /domains/{domain_id}/contract devolve um bundle YAML com vários documentos, um contrato ODCS v3.1.0 por dataset do domínio, separados por --- e ordenados pelo nome do dataset (vazio num domínio sem datasets). Cartão #148.

    • Novo

      O contrato ODCS de um dataset (GET /datasets/{dataset_id}/contract) diz a que data product pertence: tenant (nome do workspace), domain e dataProduct (nome do domínio, quando o dataset pertence a exatamente um; a vários, os nomes vão para customProperties como datavault.domains) e team com members: [{username, role: owner}], os owners pelo nome. Nunca leva emails. Cartão #148.

  46. v1.33.0

    • Novo

      tls_mode e tls_verified nas conexões (GET /connections e GET /connections/{connection_id}), só em Postgres e MySQL/MariaDB. tls_mode é o modo configurado: verify-full (cifra e verifica o certificado e o hostname do servidor, o default das conexões novas), require (cifra sem verificar) ou disable (sem TLS). Vem null numa conexão criada antes desta versão, que mantém o comportamento antigo (cifra se puder, sem verificar). tls_verified só é true com verify-full. Nos outros conectores, os dois vêm null. Cartão #449.

  47. v1.32.0

    • Novo

      Elementos de dados críticos (CDE) e dossiê regulatório. GET /cde lista os elementos críticos — um dataset ou uma coluna marcado para o BCBS 239 (bcbs239), a Solvência II (solvency2) ou outra regulação (custom), com referência livre e owner —, filtráveis por regulation e dataset_id, com o total no header X-Total-Count. GET /cde/dossier devolve o dossiê calculado na hora, por regulação e requisito (princípios 3 a 6 do BCBS 239; art. 19.º, n.os 1 a 3, do Regulamento Delegado (UE) 2015/35): cada elemento com os controlos por dimensão e o último resultado de cada regra, os problemas abertos, o SLA, a linhagem a um salto, o contrato ODCS e as lacunas, e o KPI coverage_pct (dimensões exigidas com controlo e resultado nos últimos 30 dias). Filtros regulation e domain_id. GET /cde/dossier.md e GET /cde/dossier.csv exportam o mesmo dossiê. Estados por dimensão: gap, no_result, failing, passing; por requisito também human (avaliação humana). Nenhum estado afirma conformidade. Determinístico, sem IA generativa. Cartão #392.

  48. v1.31.0

    • Novo

      suggestions_status nos datasets (GET /datasets e GET /datasets/{dataset_id}): as sugestões IA deixaram de atrasar o scan — o scan fica completed com os perfis, issues, scores e sugestões heurísticas, e a IA é gerada depois, numa fila. Valores: pending (a gerar), ready, failed (ficam as heurísticas) ou limited (acima do teto de datasets com IA por scan — ficam as heurísticas); null quando não há nada a gerar (IA desligada ou sugestões IA reutilizadas do scan anterior). O stats do scan (GET /scans/{scan_id}) ganha ai_suggestions (max_datasets, queued, limited) quando o scan deixou datasets à espera da IA; o duration_s é a duração do scan, sem a IA. Cartão #385.

  49. v1.30.0

    • Novo

      resample em POST /scans (e no ScanOut devolvido): true faz este scan ler uma amostra de linhas nova, com outra semente. Por omissão (false) cada dataset lê sempre a mesma amostra, para os clusters de duplicados e as violações de padrão não oscilarem entre scans sem os dados mudarem. Cartão #317.

    • Novo

      sample_method em dimensions_meta.unicidade de score_history (GET /datasets/{dataset_id}): como a amostra foi escolhida — system ou bernoulli (amostragem nativa TABLESAMPLE/SAMPLE da fonte), hash (hash da chave primária), stride (uma linha em cada k de um ficheiro), head (as primeiras linhas) ou full. null nos scores anteriores a esta versão. Cartão #317.

    • Alterado

      A amostra de linhas dos scans (regras pattern/required_fields, duplicados e a unicidade do score) deixa de ser «as primeiras N linhas que a fonte devolveu» e passa a ser escolhida pelo método do dialeto, com semente fixa por dataset; sample_size de dimensions_meta passa a ser o tamanho dessa amostra. O perfil da tabela (metrics sem coluna) ganha sample e value_sample (method, rows, fraction, seed, deterministic, covers_table), o impact_json do issue de duplicados ganha sample e os details dos resultados de regras avaliadas sobre a amostra também. A qualidade de rótulos lê com o mesmo método e o last_result de GET /datasets/{dataset_id}/label-quality ganha sample. No primeiro scan depois desta versão a amostra muda uma vez: clusters de duplicados, unicidade e percentagens de violação de padrão podem mudar sem os dados mudarem. Cartão #317.

  50. v1.29.0

    • Novo

      Webhooks de saída assinados (canal «Webhook genérico» dos alertas): cada entrega leva X-DataVault-Event, X-DataVault-Delivery (UUID, igual em todas as tentativas), X-DataVault-Timestamp e X-DataVault-Signature: v1=<HMAC-SHA256 do secret do canal sobre "{timestamp}.{corpo}">. Retry em 5xx, timeout e falhas de ligação (1 s, 5 s e 25 s); um 4xx é final. O corpo ganha occurred_at, e o contrato (eventos, JSON Schema do WebhookPayload, verificação em Python e Node, janela anti-replay de 5 minutos) está em docs/WEBHOOKS.md. O secret é mostrado uma vez na criação do canal ou em POST /notification-channels/{id}/rotate-secret; canais anteriores enviam sem assinatura até o rodarem. Cartão #323.

    • Alterado

      O digest semanal do webhook genérico passa a sair com event: "datavault.digest" (antes, datavault.alerts com as listas vazias), e o «Testar canal» com datavault.test. Cartão #323.

  51. v1.28.0

    • Novo

      GET /issues/{issue_id}/explanation: campos z_threshold (limiar |z| aplicado à baseline da anomalia), p_value (p-valor do modelo nulo calibrado para o tamanho da baseline) e confidence (high | medium | low, a partir do p-valor), e o objeto baseline (kind, weekday, weekday_label, points), que a resposta já calculava mas não expunha. Em anomalias anteriores, p_value e confidence vêm null e z_threshold é 3,5. Cartão #319.

    • Alterado

      Issues anomaly (GET /issues): o limiar deixou de ser |z| ≥ 3,5 fixo. Passa a depender do número de pontos da baseline (20,2 com 5, 7,3 com 8, 5,2 com 12), que tem agora de ter pelo menos 5 pontos, e cada scan aplica Benjamini–Hochberg (α = 0,05) às séries de cada dataset. Esperam-se menos anomalias em séries com ruído. O impact_json das novas anomalias traz z_threshold, p_value e confidence. Método e números do harness: docs/METODOS.md, «Anomalias». Cartão #319.

  52. v1.27.0

    • Novo

      GET /datasets/{dataset_id}/score/explain?from=&to=: «porque mudou o score?» — o Δscore entre dois scans decomposto por dimensão (peso·Δdimensão) e, dentro de cada dimensão, pelos drivers (column_nulls, duplicates, rule_failing/rule_passing, rule_set_changed, freshness, drift, …) com points em pontos de score, com sinal, e params para formatar a frase. Σ drivers + unexplained_points = delta. Por omissão compara os dois últimos scans concluídos; 422 sem dois scans com score. Cartão #318.

  53. v1.26.0

    • Novo

      dimensions_meta em cada ponto de score_history de GET /datasets/{dataset_id}: as dimensões do score calculadas sobre uma amostra e não sobre a tabela inteira — hoje só unicidade, com estimated, sample_size (as primeiras N linhas que a fonte devolveu, sem aleatoriedade) e duplicate_rows. Vazio ({}) quando todas cobrem a tabela inteira e nos scores anteriores a esta versão. Cartão #294.

    • Corrigido

      Dimensão unicidade do score (dimensions.unicidade e, por arrasto, score e latest_score): quando os duplicados são procurados numa amostra — tabelas acima de 5 000 linhas ou ficheiros amostrados —, a taxa passa a ser a da amostra, a mesma base que o issue de duplicados já usava («% da amostra»). Antes, os duplicados da amostra eram divididos pelo row_count da tabela inteira e a dimensão ficava perto de 100 em tabelas grandes. **Os scores de tabelas grandes com duplicados descem** a partir do primeiro scan depois desta versão (ex.: 500 linhas redundantes nas 5 000 lidas de uma tabela de 1 M de linhas: unicidade 90,0 em vez de 100,0, score −2,5 pontos); os scores já gravados não são recalculados. Reveja os limiares min_score de SLAs e contratos nessas tabelas.

  54. v1.25.0

    • Novo

      GET /datasets/{dataset_id}/freshness e o bloco freshness em GET /datasets/{dataset_id}: a coluna que mede a frescura do dataset — column (fixada; null = escolhida em cada scan por nome e tipo: updated/modified > ingest/loaded > created > event > outros TIMESTAMP > DATE, sem colunas de prazo, validade, fim, nascimento ou apagamento), used_column, detected_column e source (configured, detected, connector) do último perfil, latest_timestamp em UTC, timezone (aware ou assumed:<fuso>), source_timezone, future_columns (máximo mais de 24 h depois do perfil — ficam fora da escolha automática), candidates e a regra freshness do dataset (rule_id, rule_column, rule_max_age_hours). Cartão #292.

    • Novo

      source_timezone nas conexões (GET /connections, GET /connections/{connection_id}): o fuso IANA em que se leem os timestamps sem fuso da fonte (omissão UTC, o comportamento de sempre).

    • Corrigido

      Regra freshness: o parâmetro column passa a medir essa coluna (antes era ignorado e media-se a primeira coluna de data da tabela); um timestamp mais de 24 h no futuro dá a regra como falhada com details.error em vez de «fresca». Nas métricas de tabela dos perfis, latest_timestamp vem em UTC com o desvio (+00:00) e acompanhado de latest_timestamp_column e latest_timestamp_tz.

  55. v1.24.0

    • Novo

      GET /datasets/{dataset_id}/rules.dbt-tests.zip: as regras expression e custom_sql ativas do dataset como testes singulares do dbt — um ZIP com tests/*.sql (o SELECT das linhas violadoras no dialeto da fonte, com ref() no lugar da tabela; o texto de cada regra vai dentro de blocos Jinja raw, e o dbt não executa Jinja escrito numa regra) e um README com as regras que ficaram de fora e porquê.

  56. v1.23.0

    • Alterado

      POST /scans (e os pedidos de scan por agendamento, webhook do dbt Cloud e SDK): quando o workspace já tem max_queued_scans scans pedidos em fila ou a correr (5 no plano por omissão; ver o catálogo de planos), a API responde 429 com Retry-After (segundos) e o corpo {"detail", "limit": "queued_scans", "queued", "max_queued", "retry_after_s"} — é backpressure de capacidade, não o rate limit por pedido (limit distingue-os; o rate limit usa retry_after). Nada é rejeitado de forma definitiva: repetir o pedido depois de retry_after_s volta a enfileirar. Cartão #251 (escala enterprise).

  57. v1.22.0

    • Novo

      GET /governance?months=1..12 e GET /governance/domains/{domain_id}: eficácia do programa de governação (o painel do CDO). Cada KPI tem code estável, group (coverage, resolution, sla, adoption, quality, incidents, usage), unit, direction, value com a sample que o sustenta, target e target_source (workspace → organization → default; no domínio com SLA declarado, domain_sla é a meta do SLO), status (on_target, at_risk, off_target, no_data, no_target), gap, previous/delta e trend por mês de calendário UTC (o corrente com partial). KPIs: cobertura de owner, documentação, classificação, contratos e regras (ownership_pct, documentation_pct, classification_pct, contracts_pct, rules_pct); cycle_time_hours e mttr_critical_hours; slo_attainment_pct e due_date_met_pct; suggestion_adoption_pct e never_again_adoption_pct; score_<dimensão> por dimensão do scorecard; critical_incidents (uma cascata de linhagem conta como um) e active_users_pct/datasets_in_use_pct. O fluxo mede os últimos 30 dias (window=last_30d, vs. os 30 anteriores); cobertura, uso e scores o estado atual (window=now, vs. o fecho do mês anterior). O do workspace traz domains (a matriz por domínio, com semáforo por KPI) e targets. Datasets em domínios restritos sem acesso não contam.

    • Novo

      GET /governance/scorecard.csv (o scorecard executivo: uma linha por KPI com valor, meta e origem, estado, folga, variação e um valor por mês, e uma por domínio × KPI) e GET /governance/evidence.md (a evidência do programa em Markdown para o pack de procurement ou due diligence do cliente: resumo do semáforo, KPIs com meta e tendência, domínios e o método). Só agregados — sem nomes de datasets, colunas, amostras nem pessoas; células CSV protegidas contra injeção de fórmulas.

  58. v1.21.0

    • Novo

      GET /catalog/metadata-quality e GET /domains/{domain_id}/metadata-quality: qualidade do catálogo e dos metadados (KPIs de governação). pct = checks cumpridos ÷ aplicáveis (os não aplicáveis ficam fora do denominador; null sem nada medido), por dimensão (completeness, timeliness, consistency) e por check com código estável — has_owner, has_description, has_classification, has_domain, has_contract, has_rules, description_current (o schema não mudou depois da descrição/README), owner_active (owner não desativado, não saiu do workspace e com sessão nos últimos 90 dias), unused_has_owner (dataset sem uso medido tem owner ativo) e column_docs_match_schema — com coverage_pct (% dos datasets aplicáveis que cumprem). findings são os problemas de metadados (missing_owner, description_stale, owner_inactive, unused_without_owner, …) com sugestões por canal (readme, catalog_import, manual) e o endpoint que resolve; target (meta, reached, gap_pp), trend (fotografia diária; a do workspace inteiro só para quem vê o workspace inteiro), domains (por domínio) e external_catalog (cobertura e termos de glossário lidos do catálogo externo ligado). O do workspace traz os 50 piores datasets em datasets (datasets_truncated). Datasets em domínios restritos sem acesso não contam.

    • Novo

      GET /catalog/metadata-quality.csv?level=datasets|summary: export CSV para um pack de governação ou de procurement — uma linha por dataset com o estado de cada check (cumprido, falhou, n/a) e os códigos dos problemas, ou o resumo do workspace e de cada domínio com a meta e a cobertura por check. Só metadados; células protegidas contra injeção de fórmulas.

  59. v1.20.0

    • Novo

      GET /datasets/{dataset_id}/pipeline-health: a saúde dos pipelines Fivetran/Airbyte que escrevem o dataset — status (o pior entre ok, failed, delayed, paused, unknown; not_monitored sem integrador ligado) e, por pipeline, último sucesso e última falha, mensagem do integrador, cadência e atraso tolerado, a ponta de destino e a de origem (updated_at e age_s: «origem atualizada há X, destino há Y»), lag_s (quanto o destino vai atrás da origem), a reconciliação de contagens entre os perfis das duas pontas (recon, com comparable) e as tabelas que entraram/saíram do pipeline (schema_change); recent_runs traz os syncs mais recentes. Uma origem num domínio restrito aparece como «Dataset restrito», sem tabela, latência nem reconciliação.

    • Novo

      GET /orchestrator-runs aceita source=fivetran e source=airbyte: os syncs dos integradores ligados, lidos das APIs de metadados (só leitura), com o pipeline em job_id/job_name. Os issues ganham o tipo pipeline_sync (subtipos failed e delayed).

  60. v1.19.0

    • Novo

      Política de versionamento e depreciação da API (secção «Estabilidade» do portal): o que está neste portal é o contrato; uma versão minor só acrescenta; remover, renomear ou mudar o tipo ou o significado de um campo, parâmetro ou código é uma quebra e só acontece numa major. Uma operação depreciada é anunciada aqui (tipo deprecated) e responde com os headers Deprecation (RFC 9745), Sunset (RFC 8594) e Link com rel="deprecation" pelo menos 180 dias antes de deixar de responder. O CORS expõe estes três headers.

    • Novo

      GET /health passa a incluir api_version — a versão desta API, a mesma de GET /version.

    • Novo

      GET /connections/{connection_id}/query-log e GET /connections/{connection_id}/query-log/export: o que o DataVault executou na fonte, por forma de statement normalizada (sem valores) — operation (scan, discover, test), scan_id, query_tag, endpoint (primário ou réplica), execuções, erros, duração total e máxima (ms), linhas e primeira/última execução. Filtros scan_id, operation e days (1–366); a lista pagina com limit (omissão 100, máximo 500) / offset e o export devolve um download em format=csv (omissão) ou format=json.

    • Novo

      GET /connections e GET /connections/{connection_id} passam a trazer a política da fonte definida pelo DBA: blackout_timezone, blackout_windows (janelas recorrentes em hora local), blackout_active (a janela em curso, ou null), blackout_upcoming (próximas ocorrências), max_concurrent_queries e max_sample_rows. GET /connections/types passa a trazer label, group e docs_anchor de cada conector.

    • Alterado

      POST /scans responde 409 com detail = {code, message, …} quando a fonte está numa janela de blackout (code: blackout_active) ou já tem o máximo de scans em curso (code: source_busy); nenhuma query chega à fonte. Os campos novos override_blackout e override_reason (motivo com pelo menos 5 caracteres, auditado) forçam o scan dentro de uma janela, mas só para admins — com um token de API dão 403.

  61. v1.18.0

    • Novo

      Servidor MCP remoto em produção: https://mcp.praxis.lbostuff.tech/mcp (MCP Streamable HTTP, TLS). Autentica cada pedido com um token de API dvk_ (Authorization: Bearer) validado na API — sem token, 401 — e expõe as mesmas tools e resources só de leitura (incluindo get_verdict e get_trust_decision) sobre o workspace do token. Liga-se sem o código do backend: claude mcp add --transport http datavault https://mcp.praxis.lbostuff.tech/mcp --header "Authorization: Bearer dvk_…". Pedidos com um header Host fora da allowlist recebem 421 (proteção anti-DNS-rebinding) e com um Origin de outro site 403.

    • Alterado

      GET /ide/agent-config passa a devolver em produção remote_available: true, mcp_url com o MCP remoto e local_server_cmd: null: as configurações geradas para Claude Code, Claude Desktop, Cursor, VS Code e Codex apontam para ele em vez de http://127.0.0.1:8765/mcp.

  62. v1.17.0

    • Novo

      Scorecard por dimensão de qualidade (DAMA/ISO 8000): GET /datasets/{id}/dimensions devolve, para completude, unicidade, validade, atualidade, consistência, razoabilidade, exatidão e integridade, o score 0–100 do último scan (percentagem de checks aprovados), o n.º de checks, os issues abertos e o histórico por scan. Uma dimensão sem checks vem com measured: false e score: null («não medido»), nunca 100. GET /dashboard/dimensions agrega por workspace e por domínio, só com os datasets medidos (datasets_measured de datasets_total), e GET /dashboard/dimensions.csv exporta uma linha por dataset × dimensão. O score composto não muda.

    • Novo

      GET /issues aceita ?dimension= (ex.: completeness) e cada issue passa a trazer o campo dimension, resolvido pelo mapa determinístico tipo/subtipo → dimensão: cada issue cai numa só dimensão. Uma dimensão desconhecida devolve 422.

  63. v1.16.0

    • Novo

      GET /version (sem autenticação): {version, build_sha, api_version} — a versão do produto (semver, 1.0.0 na primeira release estável), os 7 hex do commit a servir e a versão desta API, que continua com semver próprio. GET /health e GET /health/ready passam a incluir build_sha. Útil para citar a versão em vigor num pedido de suporte ou num contrato.

  64. v1.15.0

    • Novo

      GET /rules, GET /suggestions, GET /reports e GET /duplicates passam a devolver o total filtrado no header X-Total-Count (os mesmos filtros do pedido, antes de limit/offset, e só o que o utilizador pode ver pelas permissões por domínio), como GET /datasets. O corpo continua a ser a lista da página; limit por omissão 50, máximo 500.

  65. v1.14.0

    • Novo

      GET /bi e GET /bi/{feed}: feeds tabulares estáveis para Excel e Power BI — scores (último score por dataset, dia e domínio), issues, slo (dataset-dia), finops (retrato do custo por dataset), activity (issues e scans) e a dimensão datasets. JSON ({feed, schema_version: 1, columns, total, limit, offset, next_offset, rows}) ou CSV (format=csv, bom=1 opcional) na mesma rota; paginação limit (≤ 10 000, omissão 5000) / offset com ordem estável; filtros since, until (UTC, janela por omissão de 90 dias em scores/slo/activity), domain_id, dataset_id e status (só issues). Colunas fixas em snake_case, datas ISO em UTC e decimais com ponto; só se acrescentam colunas no fim. ETag e If-None-Match → 304; X-Total-Count e X-Next-Offset. O catálogo traz o código Power Query (M). Só leitura, sem OData; aceita tokens de API.

  66. v1.13.0

    • Novo

      GET /ide/agent-config?tool=: configuração MCP pronta a colar para agentes de código (claude-code, claude-desktop, cursor, vscode, codex; omitido = todas) — ficheiro (.mcp.json, claude_desktop_config.json, .cursor/mcp.json, .vscode/mcp.json, ~/.codex/config.toml), comando de instalação e snippets de regras (AGENTS.md, CLAUDE.md, .cursorrules, .github/copilot-instructions.md). Nunca devolve o token: traz token_placeholder e, onde a ferramenta o permite, lê-o de DATAVAULT_TOKEN. Só leitura.

  67. v1.12.0

    • Novo

      GET /datasets/{id}/trust-facts e GET /domains/{id}/trust-facts (?detail=minimal|full, omissão minimal): factos de confiança num envelope estável (schema_version: 1) — veredito com política e decisão agente, score de qualidade e tendência 7d, trust score, contrato (estado e versão ativa), política (estado e regras violadas), contagens de sensibilidade por nível, AI-readiness por caso de uso, freshness vs alvo e attainment 30d, domínios e owner, n.º de upstream/downstream, último scan, issues abertos por severidade e links relativos; o do domínio junta um agregado e os factos de cada dataset. Só metadados: minimal nunca traz nomes de colunas. ETag (hash dos factos, sem as_of) e If-None-Match → 304; Cache-Control: private, no-cache. Só leitura, sem LLM; aceita tokens de API.

  68. v1.11.0

    • Novo

      GET /domains/{id}/readiness?use_case= (rag, ml, agente, bi; omissão bi): readiness de um data product por caso de uso — ready | ready_with_warnings | not_ready, blockers[] e warnings[] com code estável (no_datasets, no_scan, stale_scan, verdict_fail, verdict_warn, contract_invalid, ai_readiness_blocked, open_critical_issues, slo_breach_open, attainment_below_objective), dataset_id, dataset_name e message, detalhe por dataset, SLA do mês, checked_at e valid_until (próximo scan agendado). Só leitura, sem LLM; aceita tokens de API.

  69. v1.10.0

    • Novo

      Decisão de confiança (GET /datasets/{id}/trust-decision, POST /trust-decisions): campos novos required_actions[] (o que falta para subir de decisão; nunca vazio em untrusted/unknown) e valid_until (as_of + ttl_seconds). Só acrescentados — os campos, códigos e TTL anteriores não mudam. Cada consulta feita com um token de API fica no trilho de auditoria (trust_decision_checked, sem PII; o lote é um só evento).

  70. v1.9.0

    • Novo

      GET /datasets/{id}/trust-decision?purpose= e POST /trust-decisions (≤ 50 ids): decisão de confiança antes de consumir um dataset para uma finalidade (agente, rag, treino, bi) — trusted | caution | untrusted | unknown, razões com code estável e message_pt, veredito, AI-readiness, freshness vs SLA, incidentes abertos, PII sem máscara, contrato e ttl_seconds (também em Cache-Control: max-age). Só leitura; o POST aceita tokens de API.

  71. v1.8.0

    • Novo

      GET /ide/resolve?ref= e GET /ide/datasets/{id}/columns: resumo de qualidade por tabela referenciada num ficheiro SQL/dbt (score, issues abertos, contrato ativo, PII, violações da política de dados) e perfil por coluna (tipo, nulos %, distintos, classificação) — base da extensão VS Code.

    • Alterado

      POST /datasets/{id}/diff/{other_id} passa a aceitar tokens de API — o data-diff só lê as duas fontes e não persiste nada (CI e extensão VS Code).

  72. v1.7.0

    • Novo

      GET /datasets/{id}/contract/versions, GET /datasets/{id}/contract/versions/{n}, GET /datasets/{id}/contract/diff?from=&to= e GET /datasets/{id}/contract/proposals[/{id}]: versões numeradas do contrato ODCS acordado com o produtor da fonte, diff secção a secção e propostas em revisão.

    • Alterado

      GET /datasets/{id}/contract aceita source=active para descarregar o contrato aceite pelo produtor, e GET /datasets/{id}/verdict passa a validar o dataset contra esse contrato (contract.active_version): coluna prometida que desapareceu ⇒ fail; tipo divergente, obrigatória a aceitar nulos ou check sem regra ativa ⇒ warn.

  73. v1.6.0

    • Novo

      Rate limiting em toda a API: cada token de API tem um limite próprio (300 pedidos/min por omissão, além do limite por IP) e o export RGPD e o pedido de relatórios têm limites adicionais. As respostas trazem X-RateLimit-Limit, X-RateLimit-Remaining e X-RateLimit-Reset; acima do limite a API responde 429 com Retry-After (segundos) e retry_after no corpo.

  74. v1.5.0

    • Alterado

      POST /scans passa a aceitar tokens de API — orquestradores (Airflow, CI) disparam scans e esperam pelo veredito com GET /datasets/{id}/verdict. Sujeito à quota de scans do plano.

    • Novo

      GET /orchestrator-runs e POST /orchestrator-runs: runs de orquestradores (dbt Cloud, Airflow) guardados como contexto do diagnóstico de causa-raiz («o job dbt X falhou 20 min antes desta issue»). O POST aceita tokens de API; só metadados do run.

  75. v1.4.0

    • Novo

      GET /reports/{id}/trace: percurso de cada geração de relatório como grafo (fonte, âmbito, perfil, regras, anomalias, sinais, resumo, escrita, rótulo de IA, exportação, entrega), com tempos e alternativas usadas. lang=pt|en.

    • Novo

      GET /routines/blocks: catálogo versionado dos passos do pipeline de relatórios — o que entra, o que sai, o que é configurável hoje e os selos de cada passo.

  76. v1.3.0

    • Novo

      POST /rag-gate: gate de qualidade para pipelines RAG — veredito aceitar/rever/rejeitar por documento (dados pessoais, duplicados do corpus, idioma, boilerplate) antes de indexar. Aceita tokens de API; nenhum conteúdo é guardado.

  77. v1.2.0

    • Novo

      GET /datasets/{id}/verdict: veredito compacto pass/warn/fail/unknown para gates de CI.

    • Novo

      GET /datasets/{id}/schema-changes: histórico de mudanças de schema com impacto a jusante.

    • Novo

      GET /incidents e GET /incidents/{id}: issues relacionadas agrupadas num só incidente via linhagem.

    • Novo

      GET /knowledge e GET /knowledge/graph: pesquisa na base de conhecimento e grafo de relações.

    • Novo

      GET /dashboard/pii e GET /dashboard/pii.csv: mapa de PII do workspace — datasets × tipos de dado pessoal (email, NIF, telefone, morada, saúde…), origem da deteção, cobertura por regras ativas e export CSV para o DPO. Só metadados, nunca os valores.

    • Novo

      GET /dashboard/slo e GET /dashboard/slo.csv: cumprimento das slaProperties de latência do contrato ODCS face à idade observada nos perfis — attainment mensal e por dataset, violações com os issues do dia e export CSV.

    • Novo

      GET /lineage/sankey: linhagem por camada medallion (Bronze → Silver → Gold) com score, volume estimado e risco herdado de montante.

    • Novo

      GET /catalog/treemap: o catálogo inteiro agregado por fonte e schema, com score e risco.

  78. v1.1.0

    • Novo

      GET /datasets/{id}/contract (ODCS v3.1) e GET /datasets/{id}/contract.dbt.yml: contrato de dados exportável.

    • Alterado

      Tokens de API passam a estar disponíveis a partir do plano Team.

  79. v1.0.0

    • Novo

      Tokens de API dvk_* só de leitura, criados e revogados por administradores do workspace.

    • Novo

      Leitura de datasets, scans, issues, sugestões, regras, linhagem e AI-readiness em /api/v1.

    • Segurança

      Tokens guardados apenas como hash SHA-256; qualquer método além de GET devolve 403.

Ainda não tens workspace?

Começa no plano gratuito e passa a Team quando precisares de tokens de API.