> ## Documentation Index
> Fetch the complete documentation index at: https://docs.open-metadata.org/llms.txt
> Use this file to discover all available pages before exploring further.

# Create a Data Contract

> Create a new data contract for a data asset

# Create a Data Contract

Create a new data contract and attach it to a data asset. Only the `name` and `entity` reference are required — all other sections (schema, semantics, quality, SLA, security, terms of use) are optional.

## Body Parameters

<ParamField body="name" type="string" required>
  Name of the data contract, 1 to 256 characters. The contract's fully qualified name is `<entityFQN>.dataContract_<name>`.
</ParamField>

<ParamField body="entity" type="object" required>
  Reference to the data asset this contract applies to. An entity can have only one contract.

  <Expandable title="properties">
    <ParamField body="id" type="string" required>
      UUID of the entity.
    </ParamField>

    <ParamField body="type" type="string" required>
      Entity type. See [Supported Entity Types](/v2.1.x-SNAPSHOT/api-reference/data-contracts#supported-entity-types).
    </ParamField>
  </Expandable>
</ParamField>

<ParamField body="displayName" type="string">
  Human-readable display name.
</ParamField>

<ParamField body="description" type="string">
  Description in Markdown format.
</ParamField>

<ParamField body="entityStatus" type="string" default="Draft">
  Contract status: `Draft`, `In Review`, `Approved`, `Rejected`, `Deprecated`, or `Archived`.
</ParamField>

<ParamField body="schema" type="array">
  Expected columns or fields. Supported for `table`, `topic`, `apiEndpoint`, and `dashboardDataModel` only. Each item follows the Column schema. Every name must exist on the entity, and no name can repeat.

  <Expandable title="properties">
    <ParamField body="name" type="string" required>
      Column or field name.
    </ParamField>

    <ParamField body="dataType" type="string" required>
      Data type, for example `INT`, `VARCHAR`, or `TIMESTAMP`.
    </ParamField>

    <ParamField body="dataLength" type="integer">
      Length for types such as `VARCHAR`.
    </ParamField>

    <ParamField body="constraint" type="string">
      Constraint: `NULL`, `NOT_NULL`, `UNIQUE`, `PRIMARY_KEY`.
    </ParamField>

    <ParamField body="description" type="string">
      Column description.
    </ParamField>
  </Expandable>
</ParamField>

<ParamField body="semantics" type="array">
  Semantics rules evaluated against the entity's metadata when the contract is validated.

  <Expandable title="properties">
    <ParamField body="name" type="string" required>
      Rule name.
    </ParamField>

    <ParamField body="description" type="string" required>
      Rule description. Reported as the failure reason when the rule fails.
    </ParamField>

    <ParamField body="rule" type="string" required>
      [JSON Logic](https://jsonlogic.com/) expression. The rule passes when it returns `true`.
    </ParamField>

    <ParamField body="enabled" type="boolean" default="true">
      Whether the rule is evaluated.
    </ParamField>

    <ParamField body="entityType" type="string">
      Apply the rule only to this entity type.
    </ParamField>

    <ParamField body="ignoredEntities" type="array">
      Entity types the rule skips.
    </ParamField>
  </Expandable>
</ParamField>

<ParamField body="qualityExpectations" type="array">
  References to test cases that must pass. Supported for `table` only.

  <Expandable title="properties">
    <ParamField body="id" type="string" required>
      UUID of the test case.
    </ParamField>

    <ParamField body="type" type="string" required>
      Must be `testCase`.
    </ParamField>
  </Expandable>
</ParamField>

<ParamField body="sla" type="object">
  Service level agreement expectations. Stored and shown on the contract, but not checked by validation runs.

  <Expandable title="properties">
    <ParamField body="refreshFrequency" type="object">
      `interval` (integer) and `unit`: `hour`, `day`, `week`, `month`, or `year`.
    </ParamField>

    <ParamField body="maxLatency" type="object">
      `value` (integer) and `unit`: `minute`, `hour`, or `day`.
    </ParamField>

    <ParamField body="availabilityTime" type="string">
      Time of day the data should be available, for example `09:00`.
    </ParamField>

    <ParamField body="timezone" type="string" default="GMT+00:00 (Europe/London)">
      Timezone for `availabilityTime`, in the form `GMT+05:30 (Asia/Kolkata)`.
    </ParamField>

    <ParamField body="retention" type="object">
      `period` (integer) and `unit`: `day`, `week`, `month`, or `year`.
    </ParamField>

    <ParamField body="columnName" type="string">
      Column that holds the data's refresh time.
    </ParamField>
  </Expandable>
</ParamField>

<ParamField body="termsOfUse" type="string">
  Terms of use in Markdown format. Describes allowed and disallowed uses and compliance requirements. Returned as `termsOfUse.content` on the contract.
</ParamField>

<ParamField body="security" type="object">
  Security and access expectations. Stored and shown on the contract, but not enforced.

  <Expandable title="properties">
    <ParamField body="dataClassification" type="string">
      Classification of the data, for example `PII` or `Confidential`.
    </ParamField>

    <ParamField body="policies" type="array">
      Access policies. Each has `accessPolicy` (policy name), `identities` (consumer groups or users), and `rowFilters` (a list of `columnName` and `values`).
    </ParamField>
  </Expandable>
</ParamField>

<ParamField body="owners" type="array">
  Owner references (users or teams).
</ParamField>

<ParamField body="reviewers" type="array">
  Reviewer references (users or teams). When set, only a reviewer can move the contract from `In Review` to `Approved` or `Rejected`.
</ParamField>

<ParamField body="effectiveFrom" type="string">
  Date and time from which this contract is effective. Informational only.
</ParamField>

<ParamField body="effectiveUntil" type="string">
  Date and time until which this contract is effective. Informational only.
</ParamField>

<ParamField body="sourceUrl" type="string">
  Link to where the contract is maintained.
</ParamField>

<RequestExample dropdown>
  ```python POST /v1/dataContracts theme={null}
  from metadata.sdk import configure
  from metadata.sdk.entities import DataContracts
  from metadata.generated.schema.api.data.createDataContract import (
      CreateDataContractRequest,
  )

  configure(
      host="https://your-company.open-metadata.org/api",
      jwt_token="your-jwt-token"
  )

  request = CreateDataContractRequest.model_validate({
      "name": "sales-orders-contract",
      "entity": {"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "type": "table"},
      "description": "Data contract for the sales orders table",
      "entityStatus": "Approved",
      "schema": [
          {"name": "order_id", "dataType": "INT", "constraint": "PRIMARY_KEY"},
          {"name": "order_date", "dataType": "TIMESTAMP", "constraint": "NOT_NULL"},
      ],
      "semantics": [
          {
              "name": "Owners is set",
              "description": "The table must have an owner.",
              "rule": '{"and":[{"some":[{"var":"owners"},{"!=":[{"var":"fullyQualifiedName"},null]}]}]}',
              "enabled": True,
          }
      ],
      "sla": {"refreshFrequency": {"interval": 1, "unit": "day"}},
  })
  contract = DataContracts.create(request)
  print(f"Created contract: {contract.fullyQualifiedName.root}")
  ```

  ```java POST /v1/dataContracts theme={null}
  import static org.openmetadata.sdk.fluent.DataContracts.*;

  DataContract contract = create()
      .name("sales-orders-contract")
      .forEntity(new EntityReference()
          .withId(tableId)
          .withType("table"))
      .withDescription("Data contract for the sales orders table")
      .withStatus(EntityStatus.APPROVED)
      .withSchema(List.of(
          new Column().withName("order_id").withDataType(ColumnDataType.INT),
          new Column().withName("order_date").withDataType(ColumnDataType.TIMESTAMP)
      ))
      .withSemanticRule(new SemanticsRule()
          .withName("Owners is set")
          .withDescription("The table must have an owner.")
          .withRule("{\"and\":[{\"some\":[{\"var\":\"owners\"},{\"!=\":[{\"var\":\"fullyQualifiedName\"},null]}]}]}"))
      .withSla(new ContractSLA()
          .withRefreshFrequency(new RefreshFrequency()
              .withInterval(1)
              .withUnit(RefreshFrequency.Unit.DAY)))
      .execute();
  ```

  ```bash POST /v1/dataContracts theme={null}
  curl -X POST "{base_url}/api/v1/dataContracts" \
    -H "Authorization: Bearer {access_token}" \
    -H "Content-Type: application/json" \
    -d '{
      "name": "sales-orders-contract",
      "entity": {
        "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
        "type": "table"
      },
      "description": "Data contract for the sales orders table",
      "entityStatus": "Approved",
      "schema": [
        {"name": "order_id", "dataType": "INT", "constraint": "PRIMARY_KEY"},
        {"name": "order_date", "dataType": "TIMESTAMP", "constraint": "NOT_NULL"}
      ],
      "semantics": [
        {
          "name": "Owners is set",
          "description": "The table must have an owner.",
          "rule": "{\"and\":[{\"some\":[{\"var\":\"owners\"},{\"!=\":[{\"var\":\"fullyQualifiedName\"},null]}]}]}",
          "enabled": true
        }
      ],
      "sla": {
        "refreshFrequency": {"interval": 1, "unit": "day"}
      }
    }'
  ```
</RequestExample>

<ResponseExample>
  ```json Response theme={null}
  {
    "id": "f7a1b2c3-d4e5-6789-0abc-def123456789",
    "name": "sales-orders-contract",
    "fullyQualifiedName": "sample_data.ecommerce_db.shopify.sales_orders.dataContract_sales-orders-contract",
    "description": "Data contract for the sales orders table",
    "entityStatus": "Approved",
    "entity": {
      "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
      "type": "table",
      "name": "sales_orders",
      "fullyQualifiedName": "sample_data.ecommerce_db.shopify.sales_orders"
    },
    "schema": [
      {"name": "order_id", "dataType": "INT", "constraint": "PRIMARY_KEY"},
      {"name": "order_date", "dataType": "TIMESTAMP", "constraint": "NOT_NULL"}
    ],
    "semantics": [
      {
        "name": "Owners is set",
        "description": "The table must have an owner.",
        "rule": "{\"and\":[{\"some\":[{\"var\":\"owners\"},{\"!=\":[{\"var\":\"fullyQualifiedName\"},null]}]}]}",
        "enabled": true
      }
    ],
    "sla": {
      "refreshFrequency": {"interval": 1, "unit": "day"}
    },
    "version": 0.1,
    "updatedAt": 1769982800000,
    "updatedBy": "admin"
  }
  ```
</ResponseExample>

***

## Upsert (Create or Update)

Use `PUT /v1/dataContracts` with the same body to create a new contract or update an existing one.

***

## Error Handling

| Code | Error Type | Description |
| - | - | - |
| `400` | `BAD_REQUEST` | Invalid request body, an entity type or section the entity doesn't support, schema columns the entity doesn't have, or an entity that already has a contract |
| `401` | `UNAUTHORIZED` | Invalid or missing authentication token |
| `403` | `FORBIDDEN` | User lacks permission to create data contracts |
| `404` | `NOT_FOUND` | The referenced entity doesn't exist |


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.