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

# Create Semantic Layer

> Create a semantic layer for a datamart by adding table descriptions, column metadata, and feedback.

Add semantic metadata to a datamart that doesn't have a semantic layer yet. This includes table and column descriptions, synonyms, column type classifications, and global feedback for AI context.

<Warning>
  This endpoint will reject the request with `409 SEMANTIC_LAYER_ALREADY_EXISTS` if the datamart already has semantic data. Use [PUT](/developer-docs/helpers/api-reference/update-semantic-layer) to modify an existing semantic layer.
</Warning>

<Note>
  At least one of `tables` or `feedback` must be provided in the request body.
</Note>

## Authentication

This endpoint requires a **service token** in the Authorization header. Data app API tokens are not permitted and will be rejected with a `403` error.

To access your service token:

1. Go to your Databrain dashboard and open **Settings**.
2. Navigate to **Settings**.
3. Find the **Service Tokens** section.
4. Click the **"Generate Token"** button to generate a new service token if you don't have one already.

Use this token as the Bearer value in your Authorization header.

## Headers

<ParamField header="Authorization" type="string" required>
  Bearer token for API authentication. Use your service token.

  ```
  Authorization: Bearer dbn_live_abc123...
  ```
</ParamField>

<ParamField header="Content-Type" type="string" required>
  Must be set to `application/json` for all requests.

  ```
  Content-Type: application/json
  ```
</ParamField>

## Request Body

<ParamField body="datamartName" type="string" required>
  Name of the existing datamart to create a semantic layer for. Must match exactly (case-sensitive).

  <Expandable title="Finding datamart names">
    * Use the [List Datamarts API](/developer-docs/helpers/api-reference/list-datamarts) to get all datamart names
    * Names are case-sensitive and must match exactly
    * The datamart must not already have semantic data
  </Expandable>
</ParamField>

<ParamField body="tables" type="array">
  Array of table objects with semantic metadata. Each table must reference a table that exists in the datamart.

  <Expandable title="Validation rules">
    * Table `name` must match an existing table in the datamart
    * Column `name` (when provided) must match an existing column in the respective table
    * Descriptions are limited to 500 characters
    * Synonyms are limited to 10 per entity, 100 characters each
    * Synonyms must be unique (case-insensitive)
  </Expandable>
</ParamField>

<ParamField body="tables.name" type="string" required>
  Table name from the datamart. Must match an existing table.
</ParamField>

<ParamField body="tables.schemaName" type="string">
  Optional schema name for the table.
</ParamField>

<ParamField body="tables.description" type="string">
  Human-readable description of the table. Maximum 500 characters.
</ParamField>

<ParamField body="tables.synonyms" type="string[]">
  Alternative names for the table. Maximum 10 synonyms, each up to 100 characters. Must be unique (case-insensitive).
</ParamField>

<ParamField body="tables.miscellaneousInfo" type="string">
  Additional context for AI query generation. Maximum 1000 characters.
</ParamField>

<ParamField body="tables.columns" type="array">
  Array of column objects with semantic metadata.
</ParamField>

<ParamField body="tables.columns.name" type="string" required>
  Column name from the table. Must match an existing column.
</ParamField>

<ParamField body="tables.columns.description" type="string">
  Human-readable description of the column. Maximum 500 characters.
</ParamField>

<ParamField body="tables.columns.synonyms" type="string[]">
  Alternative names for the column. Maximum 10 synonyms, each up to 100 characters. Must be unique (case-insensitive).
</ParamField>

<ParamField body="tables.columns.miscellaneousInfo" type="string">
  Additional context for AI query generation. Maximum 1000 characters.
</ParamField>

<ParamField body="tables.columns.columnType" type="string">
  Semantic column type classification. Must be one of: `String`, `Long String`, `String (Custom)`, `ENUM`, `Mapper`, `Range`, `Expression`, `Identifier`, `Number`, `JSON`.

  <Expandable title="Column type compatibility">
    The column type must be compatible with the column's underlying SQL datatype. For example, `Number` cannot be assigned to a `varchar` column.
  </Expandable>
</ParamField>

<ParamField body="tables.columns.columnTypeConfig" type="object | string | null">
  Additional configuration for the column type. Must match the shape expected for `columnType`:

  * **`String`**, **`String (Custom)`**, **`ENUM`**, **`Mapper`**: plain object mapping values to descriptions (e.g. `{ "pending": "Not shipped", "shipped": "Sent" }`)
  * **`Range`**: `{ "lowerLimit": number, "upperLimit": number }` (both must be numbers)
  * **`Expression`**: string template
  * **`JSON`**: string (sample JSON)
  * **`Identifier`**, **`Number`**, **`Long String`**: omit or use `null` (non-null config is rejected)

  <Expandable title="Config validation">
    Invalid configs return `400 INVALID_COLUMN_TYPE_CONFIG` with a message describing the required shape.
  </Expandable>
</ParamField>

<ParamField body="tables.columns.isIdentifier" type="boolean">
  Mark this column as an identifier (e.g., primary key, foreign key). Defaults to `false`.
</ParamField>

<ParamField body="tables.columns.isNotIndexed" type="boolean">
  Exclude this column from AI indexing. Defaults to `false`.
</ParamField>

<ParamField body="feedback" type="string">
  Global feedback text providing context to the AI about this datamart. Maximum 2000 characters.

  <Expandable title="Feedback usage">
    * Helps guide AI-generated SQL queries
    * Example: "All monetary amounts are in USD. The fiscal year starts in April."
    * Can be used alone (without tables)
  </Expandable>
</ParamField>

## Response

On success, the response body contains only the datamart name. There is no `error` field in the JSON body when the request succeeds.

<ResponseField name="id" type="string">
  The name of the datamart (same as the input `datamartName`) on success.
</ResponseField>

## Examples

<Panel>
  <RequestExample>
    ```bash cURL - Full Example theme={"dark"}
    curl --request POST \
      --url https://api.usedatabrain.com/api/v2/data-app/datamarts/semantic-layer \
      --header 'Authorization: Bearer dbn_live_abc123...' \
      --header 'Content-Type: application/json' \
      --data '{
        "datamartName": "sales-analytics",
        "tables": [
          {
            "name": "orders",
            "description": "Customer purchase orders",
            "synonyms": ["purchases", "transactions"],
            "columns": [
              {
                "name": "order_id",
                "description": "Unique order identifier",
                "columnType": "Identifier",
                "isIdentifier": true
              },
              {
                "name": "status",
                "description": "Current order status",
                "synonyms": ["order status", "state"],
                "columnType": "ENUM"
              },
              {
                "name": "amount",
                "description": "Total order amount in USD",
                "columnType": "Number"
              }
            ]
          }
        ],
        "feedback": "This datamart covers e-commerce sales data. All amounts are in USD."
      }'
    ```

    ```bash cURL - Feedback Only theme={"dark"}
    curl --request POST \
      --url https://api.usedatabrain.com/api/v2/data-app/datamarts/semantic-layer \
      --header 'Authorization: Bearer dbn_live_abc123...' \
      --header 'Content-Type: application/json' \
      --data '{
        "datamartName": "sales-analytics",
        "feedback": "This datamart covers e-commerce sales data. Fiscal year starts April 1."
      }'
    ```

    ```javascript Node.js icon="fa-brands fa-node-js" theme={"dark"}
    const response = await fetch('https://api.usedatabrain.com/api/v2/data-app/datamarts/semantic-layer', {
      method: 'POST',
      headers: {
        'Authorization': 'Bearer dbn_live_abc123...',
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({
        datamartName: 'sales-analytics',
        tables: [
          {
            name: 'orders',
            description: 'Customer purchase orders',
            synonyms: ['purchases', 'transactions'],
            columns: [
              {
                name: 'order_id',
                description: 'Unique order identifier',
                columnType: 'Identifier',
                isIdentifier: true
              },
              {
                name: 'amount',
                description: 'Total order amount in USD',
                columnType: 'Number'
              }
            ]
          }
        ],
        feedback: 'All amounts are in USD.'
      })
    });

    const result = await response.json();

    if (result.error) {
      console.error('Create failed:', result.error.message);
    } else {
      console.log('Semantic layer created for:', result.id);
    }
    ```

    ```python Python icon="fa-brands fa-python" theme={"dark"}
    import requests

    response = requests.post(
        'https://api.usedatabrain.com/api/v2/data-app/datamarts/semantic-layer',
        headers={
            'Authorization': 'Bearer dbn_live_abc123...',
            'Content-Type': 'application/json'
        },
        json={
            'datamartName': 'sales-analytics',
            'tables': [
                {
                    'name': 'orders',
                    'description': 'Customer purchase orders',
                    'synonyms': ['purchases', 'transactions'],
                    'columns': [
                        {
                            'name': 'order_id',
                            'description': 'Unique order identifier',
                            'columnType': 'Identifier',
                            'isIdentifier': True
                        },
                        {
                            'name': 'amount',
                            'description': 'Total order amount in USD',
                            'columnType': 'Number'
                        }
                    ]
                }
            ],
            'feedback': 'All amounts are in USD.'
        }
    )

    result = response.json()

    if result.get('error'):
        print(f"Create failed: {result['error']['message']}")
    else:
        print(f"Semantic layer created for: {result['id']}")
    ```

    ```ruby Ruby icon="fa-solid fa-gem" theme={"dark"}
    require 'net/http'
    require 'json'

    uri = URI('https://api.usedatabrain.com/api/v2/data-app/datamarts/semantic-layer')
    http = Net::HTTP.new(uri.host, uri.port)
    http.use_ssl = true

    request = Net::HTTP::Post.new(uri)
    request['Authorization'] = 'Bearer dbn_live_abc123...'
    request['Content-Type'] = 'application/json'
    request.body = {
      datamartName: 'sales-analytics',
      tables: [
        {
          name: 'orders',
          description: 'Customer purchase orders',
          columns: [
            { name: 'order_id', description: 'Unique order identifier', columnType: 'Identifier' },
            { name: 'amount', description: 'Total order amount', columnType: 'Number' }
          ]
        }
      ],
      feedback: 'All amounts are in USD.'
    }.to_json

    response = http.request(request)
    result = JSON.parse(response.body)
    puts "Created: #{result['id']}"
    ```

    ```java Java icon="fa-brands fa-java" theme={"dark"}
    import java.net.http.HttpClient;
    import java.net.http.HttpRequest;
    import java.net.http.HttpResponse;
    import java.net.URI;

    public class CreateSemanticLayer {
        public static void main(String[] args) throws Exception {
            HttpClient client = HttpClient.newHttpClient();

            String requestBody = """
                {
                    "datamartName": "sales-analytics",
                    "tables": [
                        {
                            "name": "orders",
                            "description": "Customer purchase orders",
                            "columns": [
                                {
                                    "name": "order_id",
                                    "description": "Unique order identifier",
                                    "columnType": "Identifier",
                                    "isIdentifier": true
                                },
                                {
                                    "name": "amount",
                                    "description": "Total order amount in USD",
                                    "columnType": "Number"
                                }
                            ]
                        }
                    ],
                    "feedback": "All amounts are in USD."
                }""";

            HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create("https://api.usedatabrain.com/api/v2/data-app/datamarts/semantic-layer"))
                .header("Authorization", "Bearer dbn_live_abc123...")
                .header("Content-Type", "application/json")
                .POST(HttpRequest.BodyPublishers.ofString(requestBody))
                .build();

            HttpResponse<String> response = client.send(request,
                HttpResponse.BodyHandlers.ofString());
            System.out.println(response.body());
        }
    }
    ```

    ```go Go icon="fa-brands fa-golang" theme={"dark"}
    package main

    import (
        "bytes"
        "encoding/json"
        "fmt"
        "net/http"
    )

    func main() {
        body := map[string]interface{}{
            "datamartName": "sales-analytics",
            "tables": []map[string]interface{}{
                {
                    "name":        "orders",
                    "description": "Customer purchase orders",
                    "columns": []map[string]interface{}{
                        {
                            "name":         "order_id",
                            "description":  "Unique order identifier",
                            "columnType":   "Identifier",
                            "isIdentifier": true,
                        },
                        {
                            "name":        "amount",
                            "description": "Total order amount in USD",
                            "columnType":  "Number",
                        },
                    },
                },
            },
            "feedback": "All amounts are in USD.",
        }

        jsonData, _ := json.Marshal(body)

        req, _ := http.NewRequest("POST",
            "https://api.usedatabrain.com/api/v2/data-app/datamarts/semantic-layer",
            bytes.NewBuffer(jsonData))
        req.Header.Set("Authorization", "Bearer dbn_live_abc123...")
        req.Header.Set("Content-Type", "application/json")

        client := &http.Client{}
        resp, _ := client.Do(req)
        defer resp.Body.Close()

        fmt.Println("Semantic layer created")
    }
    ```

    ```php PHP icon="fa-brands fa-php" theme={"dark"}
    <?php
    $url = 'https://api.usedatabrain.com/api/v2/data-app/datamarts/semantic-layer';
    $data = [
        'datamartName' => 'sales-analytics',
        'tables' => [
            [
                'name' => 'orders',
                'description' => 'Customer purchase orders',
                'columns' => [
                    [
                        'name' => 'order_id',
                        'description' => 'Unique order identifier',
                        'columnType' => 'Identifier',
                        'isIdentifier' => true
                    ],
                    [
                        'name' => 'amount',
                        'description' => 'Total order amount in USD',
                        'columnType' => 'Number'
                    ]
                ]
            ]
        ],
        'feedback' => 'All amounts are in USD.'
    ];

    $options = [
        'http' => [
            'header' => [
                'Authorization: Bearer dbn_live_abc123...',
                'Content-Type: application/json'
            ],
            'method' => 'POST',
            'content' => json_encode($data)
        ]
    ];

    $context = stream_context_create($options);
    $response = file_get_contents($url, false, $context);
    $result = json_decode($response, true);

    echo "Created: " . $result['id'];
    ?>
    ```
  </RequestExample>

  <ResponseExample>
    ```json 200 - Success theme={"dark"}
    {
      "id": "sales-analytics"
    }
    ```

    ```json 400 - Missing datamartName theme={"dark"}
    {
      "error": {
        "code": "INVALID_REQUEST_BODY",
        "message": "\"datamartName\" is required"
      }
    }
    ```

    ```json 400 - No Section Provided theme={"dark"}
    {
      "error": {
        "code": "INVALID_REQUEST_BODY",
        "message": "\"value\" must contain at least one of [tables, feedback]"
      }
    }
    ```

    ```json 400 - Invalid Table theme={"dark"}
    {
      "error": {
        "code": "INVALID_TABLE",
        "message": "Table 'nonexistent_table' not found in datamart 'sales-analytics'"
      }
    }
    ```

    ```json 400 - Invalid Column theme={"dark"}
    {
      "error": {
        "code": "INVALID_COLUMN",
        "message": "Column 'nonexistent_col' not found in table 'orders'"
      }
    }
    ```

    ```json 400 - Incompatible Column Type theme={"dark"}
    {
      "error": {
        "code": "INVALID_COLUMN_TYPE",
        "message": "Column type 'Number' is not compatible with datatype 'varchar' for column 'status' in table 'orders'"
      }
    }
    ```

    ```json 400 - Duplicate Synonyms theme={"dark"}
    {
      "error": {
        "code": "DUPLICATE_SYNONYM",
        "message": "Duplicate synonyms for table 'orders': purchases"
      }
    }
    ```

    ```json 409 - Already Exists theme={"dark"}
    {
      "error": {
        "code": "SEMANTIC_LAYER_ALREADY_EXISTS",
        "message": "Semantic layer already exists for datamart 'sales-analytics'. Use PUT to update."
      }
    }
    ```

    ```json 403 - Data App Token theme={"dark"}
    {
      "error": {
        "code": "AUTHENTICATION_ERROR",
        "message": "Semantic Layer API requires a service token, not a data app API token"
      }
    }
    ```
  </ResponseExample>
</Panel>

## HTTP Status Code Summary

| Status Code | Description                                                   |
| ----------- | ------------------------------------------------------------- |
| `200`       | **OK** — Semantic layer created successfully                  |
| `400`       | **Bad Request** — Validation failed (see error codes below)   |
| `401`       | **Unauthorized** — Invalid or missing API token               |
| `403`       | **Forbidden** — Data app token used instead of service token  |
| `409`       | **Conflict** — Semantic layer already exists on this datamart |
| `500`       | **Internal Server Error** — Server error occurred             |

## Possible Errors

| Error Code                      | HTTP Status | Description                                            |
| ------------------------------- | ----------- | ------------------------------------------------------ |
| `INVALID_REQUEST_BODY`          | 400         | Missing required fields or validation failure          |
| `INVALID_DATAMART`              | 400         | Datamart not found                                     |
| `INVALID_TABLE`                 | 400         | Table name doesn't exist in the datamart               |
| `INVALID_COLUMN`                | 400         | Column name doesn't exist in the table                 |
| `INVALID_COLUMN_TYPE`           | 400         | Column type incompatible with the column's datatype    |
| `INVALID_COLUMN_TYPE_CONFIG`    | 400         | Column type config has wrong shape for the column type |
| `DUPLICATE_SYNONYM`             | 400         | Duplicate synonyms detected (case-insensitive)         |
| `SEMANTIC_LAYER_ALREADY_EXISTS` | 409         | Datamart already has semantic data — use PUT to update |
| `AUTHENTICATION_ERROR`          | 403         | Data app token used instead of service token           |
| `INTERNAL_SERVER_ERROR`         | 500         | Server error                                           |

## Quick Start Guide

<Steps>
  <Step title="Verify your datamart exists">
    Use the [List Datamarts API](/developer-docs/helpers/api-reference/list-datamarts) to confirm the datamart exists and note its exact name.
  </Step>

  <Step title="Prepare your semantic metadata">
    Gather descriptions, synonyms, and column type classifications for your tables:

    ```json theme={"dark"}
    {
      "datamartName": "sales-analytics",
      "tables": [
        {
          "name": "orders",
          "description": "Customer purchase orders",
          "synonyms": ["purchases"],
          "columns": [
            { "name": "order_id", "description": "Unique identifier", "columnType": "Identifier" },
            { "name": "amount", "description": "Total in USD", "columnType": "Number" }
          ]
        }
      ],
      "feedback": "All monetary values are in USD."
    }
    ```
  </Step>

  <Step title="Create the semantic layer">
    ```bash theme={"dark"}
    curl --request POST \
      --url https://api.usedatabrain.com/api/v2/data-app/datamarts/semantic-layer \
      --header 'Authorization: Bearer dbn_live_abc123...' \
      --header 'Content-Type: application/json' \
      --data '{ ... }'
    ```
  </Step>

  <Step title="Verify with GET">
    Retrieve the semantic layer to confirm it was created and check the completion score:

    ```bash theme={"dark"}
    curl --request GET \
      --url 'https://api.usedatabrain.com/api/v2/data-app/datamarts/semantic-layer?datamartName=sales-analytics' \
      --header 'Authorization: Bearer dbn_live_abc123...'
    ```
  </Step>
</Steps>

## Next Steps

<CardGroup cols={2}>
  <Card title="Get Semantic Layer" icon="eye" href="/developer-docs/helpers/api-reference/get-semantic-layer">
    Retrieve and inspect your semantic layer
  </Card>

  <Card title="Update Semantic Layer" icon="pen" href="/developer-docs/helpers/api-reference/update-semantic-layer">
    Modify your semantic layer after creation
  </Card>

  <Card title="Delete Semantic Layer" icon="trash" href="/developer-docs/helpers/api-reference/delete-semantic-layer">
    Remove semantic layer metadata
  </Card>

  <Card title="Semantic Layer Guide" icon="book" href="/guides/datasources/semantic-layer">
    Configure the semantic layer in the Databrain UI
  </Card>
</CardGroup>
