> ## Documentation Index
> Fetch the complete documentation index at: https://platform.atlan.com/llms.txt
> Use this file to discover all available pages before exploring further.

> ## Agent Instructions
> To act on Atlan objects, use the Atlan MCP server at https://api.atlan.com/mcp or the atlanai CLI; `atlanai --map json` prints its command map. Run a read-only identity check before any write.
> The docs MCP server at /mcp searches these docs only. It cannot read or change Atlan objects.
> SDK packages: Python `atlanai` (PyPI) and TypeScript `@atlanai/sdk` (npm). Show Python first, then TypeScript.

# Map an ontology to physical data

> Declare, validate, publish, export, and retrieve governed physical mappings for one exact ontology release.

# Map an ontology to physical data

> Give agents versioned physical names and join declarations without giving the Ontology service warehouse credentials.

An ontology binding maps one immutable ontology release to user-declared
physical identities. A binding can name tables, views, fields, registered
transformations, governed joins, or a read-only SQL-backed relation. The
extension validates and versions those declarations. It does not connect to a
source, verify that a physical name exists, generate executable SQL, or run a
query.

```text theme={null}
ontology release -> binding drafts -> validation -> binding release -> bounded agent context
```

<Note>
  **Preview.** An administrator must install both the Ontology and Ontology
  Binding extensions before these routes, artifact kinds, Studio pages, and MCP
  tools are available.
</Note>

## Before you start

Set the Gateway URL, bearer token, workspace, and exact Ontology release. Core
Registry release IDs use the `rel_...` form.

```bash theme={null}
export ATLAN_GATEWAY_URL="https://api.atlan.com"
export ATLAN_TOKEN="..."
export WORKSPACE_ID="workspace_01example"
export ONTOLOGY_ID="ontology_01example"
export ONTOLOGY_RELEASE_ID="rel_01example"
export ONTOLOGY_RELEASE="1.0.0"
export ONTOLOGY_MANIFEST_DIGEST="0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
```

The examples use Snowflake names, but qualified names are source-neutral
strings. SQL-backed relations support `ansi`, `big_query`, `databricks`,
`postgres`, and `snowflake` dialects.

## Use the Data bindings view

Open Ontology Studio, select an ontology with a published release, then choose
**Data bindings**. The view can:

1. Create a binding family pinned to an exact Ontology release.
2. Add object, property, and link mappings.
3. Describe a direct table or view, or a SQL-backed virtual relation.
4. Validate the complete mapping graph.
5. Publish and inspect immutable binding releases.
6. Preview the context an agent receives.
7. Export or import portable binding JSON.

Saving a mapping appends a draft version. Existing releases remain pinned to
the versions they published.

## Create a binding family

The binding root records the exact logical release, a physical source scope,
and its compatibility policy:

```bash theme={null}
BINDING=$(curl -sS --fail-with-body \
  -X POST "${ATLAN_GATEWAY_URL}/registry/v1/artifacts/ontology_binding" \
  -H "Authorization: Bearer ${ATLAN_TOKEN}" \
  -H "Content-Type: application/json" \
  --data "$(jq -n \
    --arg workspace_id "${WORKSPACE_ID}" \
    --arg ontology_id "${ONTOLOGY_ID}" \
    --arg release_id "${ONTOLOGY_RELEASE_ID}" \
    --arg release "${ONTOLOGY_RELEASE}" \
    --arg digest "${ONTOLOGY_MANIFEST_DIGEST}" \
    '{
      name: "customer-360-snowflake",
      display_name: "Customer 360 Snowflake",
      workspace_id: $workspace_id,
      api_name: "customer_360_snowflake",
      ontology_release: {
        ontology_id: $ontology_id,
        release_id: $release_id,
        release: $release,
        manifest_digest: $digest
      },
      source_scope: {
        source: {kind: "source", qualified_name: "snowflake.customer_360"}
      },
      compatibility_policy: "backward_compatible"
    }')")

BINDING_ID=$(jq -r '.id' <<<"${BINDING}")
```

The policy can be `none`, `backward_compatible`, or `full_compatible`.

## Add an object mapping

An object mapping pins one exact logical object version and declares its
physical relation and row grain:

```bash theme={null}
CUSTOMER_OBJECT_BINDING=$(curl -sS --fail-with-body \
  -X POST "${ATLAN_GATEWAY_URL}/registry/v1/artifacts/ontology_object_binding" \
  -H "Authorization: Bearer ${ATLAN_TOKEN}" \
  -H "Content-Type: application/json" \
  --data "$(jq -n \
    --arg workspace_id "${WORKSPACE_ID}" \
    --arg binding_id "${BINDING_ID}" \
    '{
      name: "customer-360-customer",
      display_name: "Customer",
      workspace_id: $workspace_id,
      binding_id: $binding_id,
      api_name: "customer",
      ontology_object: {
        kind: "ontology_object_type",
        artifact_id: "ontology_object_type_01example",
        version_ordinal: 1,
        content_hash: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
      },
      relation: {
        kind: "relation",
        qualified_name: "CUSTOMER_DB.C360.CUSTOMERS"
      },
      grain: {
        description: "One row per customer.",
        uniqueness: ["customer_id"]
      }
    }')")

CUSTOMER_OBJECT_BINDING_ID=$(jq -r '.id' <<<"${CUSTOMER_OBJECT_BINDING}")
```

The extension treats the qualified name as governed metadata. It does not look
up `CUSTOMER_DB.C360.CUSTOMERS` in Snowflake.

### Declare a SQL-backed relation

Use a query-backed relation when the logical object is implemented by a
bounded read-only query rather than one table or view:

```json theme={null}
{
  "mode": "query_backed",
  "query": {
    "dialect": "snowflake",
    "sql": "SELECT customer_id, status FROM CUSTOMER_DB.C360.CUSTOMERS WHERE is_deleted = FALSE",
    "default_catalog": "CUSTOMER_DB",
    "default_schema": "C360",
    "outputs": [
      {"name": "customer_id", "physical_type": "VARCHAR", "nullable": false},
      {"name": "status", "physical_type": "VARCHAR", "nullable": true}
    ],
    "dependencies": [
      {"kind": "relation", "qualified_name": "CUSTOMER_DB.C360.CUSTOMERS"}
    ]
  }
}
```

The extension parses and versions the declaration. The calling agent or query
gateway remains responsible for execution with customer-controlled credentials.

## Add property and link mappings

A property mapping connects a logical property to a field:

```json theme={null}
{
  "name": "customer-360-customer-id",
  "display_name": "Customer ID",
  "workspace_id": "workspace_01example",
  "binding_id": "ontology_binding_01example",
  "api_name": "customer_customer_id",
  "object_binding_id": "ontology_object_binding_01example",
  "ontology_property_api_name": "customer_id",
  "implementation": {
    "kind": "field",
    "field": {
      "kind": "field",
      "qualified_name": "CUSTOMER_DB.C360.CUSTOMERS.CUSTOMER_ID"
    }
  }
}
```

Create it with `POST /registry/v1/artifacts/ontology_property_binding`. A
registered transformation can instead name a transformation and its output
field.

A link mapping connects two object mappings through one or more governed
property-binding pairs:

```json theme={null}
{
  "name": "customer-has-case",
  "display_name": "Customer has case",
  "workspace_id": "workspace_01example",
  "binding_id": "ontology_binding_01example",
  "api_name": "customer_has_case",
  "ontology_link": {
    "kind": "ontology_link_type",
    "artifact_id": "ontology_link_type_01example",
    "version_ordinal": 1,
    "content_hash": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
  },
  "source_object_binding_id": "ontology_object_binding_01customer",
  "target_object_binding_id": "ontology_object_binding_01case",
  "join_keys": [
    {
      "source_property_binding_id": "ontology_property_binding_01customerid",
      "target_property_binding_id": "ontology_property_binding_01casecustomerid"
    }
  ]
}
```

Create it with `POST /registry/v1/artifacts/ontology_link_binding`. Validation
checks that the mappings resolve, the logical endpoints agree, and joined
logical property types are compatible.

## Validate and publish

Build `source_versions` from the exact root and mapping versions returned by
Registry. Each item contains `kind`, `artifact_id`, `version_ordinal`, and
`content_hash`.

```bash theme={null}
VALIDATION=$(curl -sS --fail-with-body \
  -X POST "${ATLAN_GATEWAY_URL}/ontology_binding/v1/validations" \
  -H "Authorization: Bearer ${ATLAN_TOKEN}" \
  -H "Content-Type: application/json" \
  --data "$(jq -n \
    --arg binding_id "${BINDING_ID}" \
    --argjson source_versions "${SOURCE_VERSIONS}" \
    '{binding_id: $binding_id, source_versions: $source_versions}')")

jq '{is_valid, diagnostics, resource_count, manifest_digest}' <<<"${VALIDATION}"
```

Publish only the validated versions:

```bash theme={null}
BINDING_RELEASE=$(curl -sS --fail-with-body \
  -X POST "${ATLAN_GATEWAY_URL}/ontology_binding/v1/releases" \
  -H "Authorization: Bearer ${ATLAN_TOKEN}" \
  -H "Content-Type: application/json" \
  --data "$(jq -n \
    --arg binding_id "${BINDING_ID}" \
    --argjson source_versions "${SOURCE_VERSIONS}" \
    '{binding_id: $binding_id, release: "1.0.0", source_versions: $source_versions}')")

BINDING_RELEASE_ID=$(jq -r '.id' <<<"${BINDING_RELEASE}")
```

The native operation appends an immutable publication snapshot to the binding
root and releases that exact version through Core Registry. List or read it
through:

```text theme={null}
GET /ontology_binding/v1/bindings/{binding_id}/releases
GET /ontology_binding/v1/bindings/{binding_id}/releases/{release_id}/schema
GET /registry/v1/artifacts/ontology_binding/{binding_id}/releases/latest
```

## Retrieve bounded mapping context

```bash theme={null}
curl -sS --fail-with-body \
  -X POST "${ATLAN_GATEWAY_URL}/ontology_binding/v1/context-queries" \
  -H "Authorization: Bearer ${ATLAN_TOKEN}" \
  -H "Content-Type: application/json" \
  --data "$(jq -n \
    --arg binding_id "${BINDING_ID}" \
    --arg release_id "${BINDING_RELEASE_ID}" \
    '{
      binding_id: $binding_id,
      release_id: $release_id,
      query: "customer status and support cases",
      max_resources: 12,
      max_depth: 2,
      max_tokens: 4000,
      diagnostics: true
    }')" | jq
```

The response pairs logical definitions with their released physical mappings.
Pass `ontology_release_id` to test reuse against a newer release of the same
ontology. Reuse succeeds only when every referenced logical resource keeps its
exact version and content hash.

An MCP client reaches the same read-only operation as
[`ontology_binding__get_context`](/tools/mcp/ontology/references/ontology-binding-get-context).

## Export a portable binding

Export one exact binding release as deterministic, credential-free JSON:

```bash theme={null}
PORTABLE_EXPORT=$(curl -sS --fail-with-body \
  -X POST "${ATLAN_GATEWAY_URL}/ontology_binding/v1/exports" \
  -H "Authorization: Bearer ${ATLAN_TOKEN}" \
  -H "Content-Type: application/json" \
  --data "$(jq -n \
    --arg binding_id "${BINDING_ID}" \
    --arg release_id "${BINDING_RELEASE_ID}" \
    '{binding_id: $binding_id, release_id: $release_id}')")

jq '{format, document_digest, binding_manifest_digest}' <<<"${PORTABLE_EXPORT}"
```

The `document` uses logical API names rather than environment-specific
artifact IDs. It contains physical declarations, but no credentials or source
data. A release containing legacy artifact-based physical references cannot be
exported portably; append qualified physical names and publish a new release.

## Import portable binding JSON

Preview the document against one exact destination Ontology release:

```bash theme={null}
IMPORT_PREVIEW_REQUEST=$(jq -n \
  --arg document "$(jq -r '.document' <<<"${PORTABLE_EXPORT}")" \
  --arg ontology_id "${ONTOLOGY_ID}" \
  --arg release_id "${ONTOLOGY_RELEASE_ID}" \
  --arg release "${ONTOLOGY_RELEASE}" \
  --arg digest "${ONTOLOGY_MANIFEST_DIGEST}" \
  --arg workspace_id "${WORKSPACE_ID}" \
  '{
    document: $document,
    ontology_release: {
      ontology_id: $ontology_id,
      release_id: $release_id,
      release: $release,
      manifest_digest: $digest
    },
    workspace_id: $workspace_id,
    binding_api_name: "customer_360_imported",
    display_name: "Customer 360 imported"
  }')

IMPORT_PREVIEW=$(curl -sS --fail-with-body \
  -X POST "${ATLAN_GATEWAY_URL}/ontology_binding/v1/imports/preview" \
  -H "Authorization: Bearer ${ATLAN_TOKEN}" \
  -H "Content-Type: application/json" \
  --data "${IMPORT_PREVIEW_REQUEST}")

jq '{preview_id, is_valid, diagnostics, object_count, property_count, link_count}' \
  <<<"${IMPORT_PREVIEW}"
```

Apply the unchanged valid preview:

```bash theme={null}
curl -sS --fail-with-body \
  -X POST "${ATLAN_GATEWAY_URL}/ontology_binding/v1/imports/apply" \
  -H "Authorization: Bearer ${ATLAN_TOKEN}" \
  -H "Content-Type: application/json" \
  --data "$(jq \
    --arg preview_id "$(jq -r '.preview_id' <<<"${IMPORT_PREVIEW}")" \
    '. + {preview_id: $preview_id}' <<<"${IMPORT_PREVIEW_REQUEST}")" | \
  jq '{binding_id, created_count}'
```

Apply recomputes the preview and creates the binding root and every mapping in
one Registry transaction. It creates drafts and does not publish a binding
release. Preview and apply never contact a physical source.

## Verify the boundary

Before handing a binding release to an agent, verify:

* Both the Ontology and binding release IDs are exact `rel_...` handles.
* Validation returned `is_valid: true` for the versions you published.
* The binding response carries both manifest digests.
* Qualified physical names and SQL declarations contain no credentials.
* The calling agent or executor uses a separately governed source connection.

<CardGroup cols={2}>
  <Card title="Publish a logical model" icon="diagram-project" href="/cookbooks/how-tos/ontology">
    Define and publish the logical resources that a binding references.
  </Card>

  <Card title="Get binding context" icon="plug" href="/tools/mcp/ontology/references/ontology-binding-get-context">
    Give an agent bounded logical definitions and released physical mappings.
  </Card>
</CardGroup>
