Databricks logoAPI

Every Endpoint of the CoreModels Databricks Integration, With Real Payloads

Reference articles usually show the happy path and gesture at the rest. This one is the full inventory: every HTTP route the CoreModels Databricks Unity Catalog connector answers on, the role each one enforces, the request and response bodies as they actually are, and — where a verb lives on one surface but not the other — an explicit statement of that fact rather than a diagram that implies otherwise.

Every Endpoint of the CoreModels Databricks Integration, With Real Payloads

Reference articles usually show the happy path and gesture at the rest. This one is the full inventory: every HTTP route the CoreModels Databricks Unity Catalog connector answers on, the role each one enforces, the request and response bodies as they actually are, and — where a verb lives on one surface but not the other — an explicit statement of that fact rather than a diagram that implies otherwise.

There are two surfaces by design. The interactive surface under graph/integrations/... authenticates with your normal CoreModels login token and carries every verb. The machine-to-machine surface under /v1/... accepts CoreModels user API keys — the kind you put in CI secrets — and deliberately carries only audit and badge. Base URL is written as https://coremodels.example.com; the vendor key is databricks; {projectId} is the 32-character hex id of the governing project.

Any JSON route with an unrecognized vendor key answers success: false with Unknown vendor '<key>'. Registered: <comma-joined keys>. — useful, because the registered list doubles as discovery when you can't remember a key. (The badge routes, which must return an image, render a gray unknown vendor badge instead.)

Discovery — GET graph/integrations/vendors (any authenticated user)

GET https://coremodels.example.com/graph/integrations/vendors
Authorization: Bearer $TOKEN

Lists every registered connector. The Databricks entry:

{ "key": "databricks", "displayName": "Databricks Unity Catalog",
  "capabilities": "Import, Audit, Generate",
  "artifacts": {
    "information_schema": "required — JSON rows of system.information_schema COLUMNS × TABLES (documented query)",
    "keys": "optional — flattened PK/FK constraint rows (documented query)",
    "lineage": "optional — system.access.table_lineage rows; becomes Depends-On lineage"
  } }

All three capabilities are real for this connector, so every section below has substance — including Generate. (Some connectors are Import + Audit only and ship no generator; Databricks is not one of them.)

Import — POST graph/integrations/databricks/import/{projectId} — Admin

The one verb that writes governed meaning, and it writes additively: existing governed nodes are never mutated or deleted; re-imports skip what is already governed and only vendor bookkeeping is refreshed. The body maps artifact names to raw contents — each value is the JSON text of one extract:

POST https://coremodels.example.com/graph/integrations/databricks/import/{projectId}
Authorization: Bearer $TOKEN
Content-Type: application/json

{ "artifacts": { "information_schema": "<information_schema.json contents>",
                 "keys": "<keys.json contents>",
                 "lineage": "<lineage.json contents>" },
  "spaces": [] }

spaces is optional; empty means the project's main space. Omitting artifacts entirely earns the exact error Body must include 'artifacts': { "<name>": "<content>" } (e.g. manifest for dbt). — the example names dbt because the message is shared across all connectors. The response reports counts (datasetsAdded, datasetsSkippedExisting, fieldsAdded, lineageEdgesAdded, lineageEdgesSkipped, nodesEnriched), a snapshotStored flag (the parsed estate snapshot that powers re-audit), plus lossiness and errors arrays. Lossiness is a success channel: the import proceeded, and this is what it approximated or dropped.

Audit — POST graph/integrations/databricks/audit/{projectId} — Viewer

Read-only, always. recordHistory (default false) is the one piece of opt-in bookkeeping: set it to record this run in the rolling audit trail.

POST https://coremodels.example.com/graph/integrations/databricks/audit/{projectId}
Authorization: Bearer $TOKEN
Content-Type: application/json

{ "artifacts": { "information_schema": "<information_schema.json contents>" },
  "recordHistory": true }

The response is the full audit report:

{
  "success": true,
  "vendor": "databricks", "projectName": "main",
  "errorCount": 0,          // the CI-gate signal: > 0 means governed meaning was violated
  "warningCount": 2, "infoCount": 3,
  "codes": { "key-column-undeclared": 2, "table-no-comment": 3 },
  "driftedObjects": [],     // vendor identities of drifted objects
  "fingerprint": "9f2c4a1b0e77d3aa",   // content hash of the artifacts
  "metrics": { "Datasets (estate)": "18",
               "Datasets governed": "18 / 18",
               "Fields governed": "150 / 150",
               "Governed nodes with canonical mappings": "0 / 168 (0%)",
               "Last import": "2026-08-02T14:21:07.3310000+00:00" },
  "findings": [ { "section": "Conformance", "severity": "Warning",
                  "code": "key-column-undeclared", "subject": "main.sales.orders.customer_id",
                  "message": "…", "detail": null } ],
  "markdown": "…the PR-comment-ready report…",
  "historyRecorded": true,
  "lossiness": []
}

Sections are Coverage, Drift, and Conformance; severities are Error, Warning, Info. The Databricks-specific conformance codes are table-no-comment (Info) and key-column-undeclared (Warning); the coverage and drift codes are shared across all connectors.

metrics is the headline summary the Markdown report renders as a table: how many datasets the extract contained, how many of them resolve to governed Types, the same ratio for fields, and the canonical-mapping coverage — how many vendor-governed nodes also carry a mapping to a non-vendor standard, which is the number to watch if you are grounding agents or exporting to another format. Last import appears once an import has been recorded.

Re-audit — POST graph/integrations/databricks/reaudit/{projectId} — Viewer

The audit above asks "do these fresh artifacts still conform to the governed model?" The re-audit asks the reverse: "the governed model changed — does the last-known estate still conform?" It needs no artifacts because it runs against the snapshot stored at import time:

POST https://coremodels.example.com/graph/integrations/databricks/reaudit/{projectId}
Authorization: Bearer $TOKEN
Content-Type: application/json

{}

The body optionally takes projectName (the vendor-side project to re-audit; null means the latest stored snapshot), spaces, and notifySlack (default false), which posts the run to the project's configured Slack channel when it carries errors or warnings. The response has the same report shape as audit, with one behavioral difference: a re-audit run is always recorded in the history — there is no recordHistory flag to forget. If the import ever reported snapshotStored: false (the snapshot exceeded the storage cap of roughly 1.5 MB), there is nothing stored to re-audit against, and fresh-artifact audits are the fallback.

History — GET graph/integrations/databricks/history/{projectId} — Viewer

GET https://coremodels.example.com/graph/integrations/databricks/history/{projectId}
Authorization: Bearer $TOKEN

Returns the rolling audit trail, newest first, grouped by vendor-side project:

{ "success": true, "vendor": "databricks",
  "projects": [ { "projectName": "main",
                  "runs": [ { "at": "2026-08-03T09:12:44.6183920+00:00", "trigger": "ci",
                              "errorCount": 0, "warningCount": 2, "infoCount": 3,
                              "codes": { "key-column-undeclared": 2, "table-no-comment": 3 },
                              "fingerprint": "9f2c4a1b0e77d3aa" } ] } ] }

trigger records how the run happened, and the values are lowercase: audit (an interactive audit called with recordHistory), ci (the machine-to-machine audit), reaudit, and scheduled (the server-side heartbeat, where a deployment enables it). Run records are deliberately compact — counts, per-code totals, fingerprint — because the trail answers "is this estate drifting over time?" while a live audit answers "what exactly is wrong now?"

Badge — GET graph/integrations/databricks/badge/{projectId} — Viewer

Returns image/svg+xml: a self-contained shields-style badge labeled databricks audit, rendered from the latest recorded run. Green (#4c1) means clean, yellow (#dfb317) means warnings only, red (#e05d44) means errors, gray (#9f9f9f) means no recorded runs.

Generate — POST graph/integrations/databricks/generate/{projectId} — Viewer

Read-only in the graph sense: it reads governed meaning and emits vendor artifacts for you to review and apply.

POST https://coremodels.example.com/graph/integrations/databricks/generate/{projectId}
Authorization: Bearer $TOKEN
Content-Type: application/json

{ "typeNames": [] }

typeNames restricts generation to named types; empty means everything eligible. (The body also accepts targetVersion and extra for connectors with dialect choices; the Databricks generator currently has a single dialect, so typeNames is the option that matters.) The response:

{ "success": true,
  "artifacts": [ { "name": "coremodels_delta_tables.sql", "kind": "sql",
                   "content": "-- Generated by CoreModels — governed Delta table definitions.\n…" } ],
  "lossiness": [ { "kind": "StructuralDrop", "path": "orders_view",
                   "explanation": "Views are derived objects; DDL generation covers tables only." } ],
  "errors": [] }

One artifact comes back: CREATE TABLE IF NOT EXISTS … USING DELTA statements with NOT NULL from governed checks, one informational PRIMARY KEY constraint per table, FOREIGN KEY … REFERENCES from governed references, and taxonomy allowed values carried on column COMMENTs. Views are skipped with declared lossiness, as the sample shows. If nothing is eligible, generation fails honestly with No eligible tables found to generate DDL for.

Status — GET graph/integrations/databricks/status/{projectId} — Viewer

GET https://coremodels.example.com/graph/integrations/databricks/status/{projectId}
Authorization: Bearer $TOKEN

Answers "has this project imported a Databricks estate, and what does it look like now?": imported (boolean), state (the last-import bookkeeping), and governedDatasets — how many Unity Catalog identities currently resolve to governed Types.

The state record for this connector carries the vendor key, the vendor-side project name (your catalog), importedAt as an ISO-8601 timestamp, a compact counts string (fieldsAdded=…, lineageAdded=…, lineageSkipped=…, nodesEnriched=…), the artifact fingerprint, and the parser's facts — for Databricks, the table and view totals. The tool-version and artifact-version slots stay empty here by nature: a Unity Catalog SQL extract carries no generating tool version, unlike, say, a build manifest that stamps one.

Reconcile — POST graph/integrations/reconcile/{projectId} — Admin

Not vendor-scoped in the route, but part of the surface you will reach for once a lakehouse is governed from two sides — the Unity Catalog metadata on one, whatever transformation tool materializes into it on the other. It finds datasets that two imported estates describe as the same physical relation, matched on database.schema.table, and links each pair with reciprocal sameAs mappings:

POST https://coremodels.example.com/graph/integrations/reconcile/{projectId}
Authorization: Bearer $TOKEN
Content-Type: application/json

{ "vendorA": "databricks", "vendorB": "dbt" }

The response reports linksWritten, the matched pairs (both vendor ids, the physical name, the count of matched fields), and unmatchedA / unmatchedB so you can see what did not line up. It is idempotent — re-running after the next import refreshes the links rather than duplicating them.

Sync plans — POST graph/integrations/databricks/sync/propose/{projectId} — Viewer

The newest part of the surface. Propose takes the same artifacts body as audit and classifies the fresh extract three-way — against the estate snapshot stored at import and the per-node governed sync bases — into a reviewable, replayable plan, returned inline. It is read-only against governed meaning; its only writes are bookkeeping (the stored plan plus a ledger entry, superseding earlier proposals). Two Viewer reads complete it: GET graph/integrations/sync/plan/{projectId}/{planId} fetches a stored plan, and GET graph/integrations/sync/ledger/{projectId} (optionally ?vendor=databricks) lists the compact plan history per vendor-side project, newest first.

The machine-to-machine surface (/v1)

Two routes, both Viewer role, both taking user API keys — everything CI needs and nothing it doesn't:

POST https://coremodels.example.com/v1/{projectId}/integrations/databricks/audit
Authorization: Bearer $TOKEN
Content-Type: application/json

{ "artifacts": { "information_schema": "<information_schema.json contents>" },
  "recordHistory": true }

Same request body as the interactive audit; the response is wrapped in the standard ApiResponse envelope, so the report fields live under data — the CI gate reads data.errorCount, and data.markdown is the report for your job summary. Runs recorded from this surface carry trigger ci. The second route is the same badge as above:

GET https://coremodels.example.com/v1/{projectId}/integrations/databricks/badge
Authorization: Bearer $TOKEN

And the honest boundary: reaudit, history, import, generate, status, reconcile, and the sync-plan routes live on the interactive surface only. If your automation needs re-audit on a schedule, that is what the server-side scheduled re-audit (a deployment configuration, off by default) is for — it runs against stored snapshots and records into the same history the routes above read.

Role summary

RouteRole
GET graph/integrations/vendorsany authenticated
POST …/databricks/import/{projectId}Admin
POST …/databricks/audit/{projectId}Viewer
POST …/databricks/reaudit/{projectId}Viewer
GET …/databricks/history/{projectId}Viewer
GET …/databricks/badge/{projectId}Viewer
POST …/databricks/generate/{projectId}Viewer
GET …/databricks/status/{projectId}Viewer
POST graph/integrations/reconcile/{projectId}Admin
POST …/databricks/sync/propose/{projectId}Viewer
GET graph/integrations/sync/plan/{projectId}/{planId}Viewer
GET graph/integrations/sync/ledger/{projectId}Viewer
POST v1/{projectId}/integrations/databricks/auditViewer (API key)
GET v1/{projectId}/integrations/databricks/badgeViewer (API key)

Import and reconcile are the only verbs that need Admin, because they are the only two that write governed meaning to the graph. Everything else — including generate, which writes files for you rather than nodes for the graph — runs at Viewer.

For worked end-to-end examples of these calls, see the Databricks quickstart in the CoreModels documentation.