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

# Create Schema

> Connect DynamoSQL to DynamoDB tables in your AWS account.

<Note>
  Required scope: `schemas:write`
</Note>

Before creating a schema, follow the [IAM Setup](/guides/iam-setup) guide to configure the trust policy and permissions DynamoSQL needs to assume your role. After creating a schema, use [Validate Role](/api-reference/schemas/validate-role) to confirm the configuration is correct.


## OpenAPI

````yaml POST /v1/schemas
openapi: 3.0.3
info:
  title: DynamoSQL API
  version: 0.1.0
  license:
    name: Proprietary
    url: https://dynamosql.com
  description: >
    Complete API for DynamoSQL — authentication, SQL query planning and

    execution, schema management, and usage metering.


    All endpoints are reachable at `api.dynamosql.com`.


    **Authentication** uses `POST /v1/auth/token` with your API client

    credentials. See the [Authentication
    guide](https://docs.dynamosql.com/guides/authentication)

    for the full token exchange flow.


    **API client scopes** control which endpoints a programmatic client can
    access.

    Valid scopes: `query`, `schemas:read`, `schemas:write`, `usage:read`.

    Endpoints note their required scope in their description.


    **Error responses** always follow the same envelope:

    ```json

    { "success": false, "error": { "message": "..." } }

    ```
servers:
  - url: https://api.dynamosql.com
    description: Production
security:
  - cognitoJwt: []
tags:
  - name: Authentication
    description: >
      Obtain a JWT bearer token using your API client credentials. This token is
      required for all other endpoints. See the Authentication guide for details
      on the token exchange flow and scope management.
  - name: Query
    description: SQL planning and execution.
  - name: Schemas
    description: >
      Connect DynamoSQL to DynamoDB tables in your AWS account. A schema pairs a
      name with the IAM role and AWS region DynamoSQL uses to assume
      cross-account access.
  - name: Usage
    description: Metered usage — requests, rows returned, and DynamoDB read units.
paths:
  /v1/schemas:
    post:
      tags:
        - Schemas
      summary: Create schema
      description: >
        Creates a new schema connecting DynamoSQL to DynamoDB tables in your AWS
        account via cross-account IAM role assumption.


        After creation, DynamoSQL kicks off a background metadata refresh that
        discovers the tables visible to the role and caches their key schema and
        index configuration. This is non-blocking — the schema is usable for
        queries immediately, but column and index hints may not appear in the
        portal until the first refresh completes.


        **Before calling this endpoint**, set up the IAM role in your AWS
        account following the [IAM Setup
        guide](https://docs.dynamosql.com/guides/iam-setup). Use `POST
        /v1/schemas/{schemaName}/validate-role` to confirm the role is correctly
        configured before issuing queries.


        API clients require the `schemas:write` scope.
      operationId: createSchema
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SchemaCreateRequest'
            examples:
              basic:
                summary: Schema with explicit table allowlist
                value:
                  schemaName: myschema
                  region: us-east-1
                  accountId: '123456789012'
                  roleArn: arn:aws:iam::123456789012:role/DynamoSQLReadRole
                  externalId: dsql-ext-7f3a9c2b
                  tableAllowlist:
                    - Users
                    - Orders
                    - Products
              wildcard:
                summary: Schema allowing all tables
                value:
                  schemaName: myschema
                  region: us-east-1
                  accountId: '123456789012'
                  roleArn: arn:aws:iam::123456789012:role/DynamoSQLReadRole
                  externalId: dsql-ext-7f3a9c2b
      responses:
        '201':
          description: Schema created. A background metadata refresh has been started.
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/ApiResponse'
                  - type: object
                    properties:
                      data:
                        $ref: '#/components/schemas/Schema'
              example:
                success: true
                data:
                  tenantId: tenant-abc123
                  schemaName: myschema
                  region: us-east-1
                  accountId: '123456789012'
                  roleArn: arn:aws:iam::123456789012:role/DynamoSQLReadRole
                  externalId: dsql-ext-7f3a9c2b
                  tableAllowlist:
                    - Users
                    - Orders
                    - Products
                  status: active
                  createdAt: '2026-03-11T10:00:00.000Z'
                  updatedAt: '2026-03-11T10:00:00.000Z'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '409':
          $ref: '#/components/responses/Conflict'
components:
  schemas:
    SchemaCreateRequest:
      type: object
      required:
        - schemaName
        - region
        - accountId
        - roleArn
        - externalId
      properties:
        schemaName:
          type: string
          description: >
            Logical name for this schema. Used in SQL as the schema qualifier:
            `SELECT * FROM {schemaName}.{tableName}`. Must be unique within the
            tenant. Case-insensitive at query time; stored as-provided.
          example: myschema
        region:
          type: string
          description: >
            AWS region where the DynamoDB tables reside. Must be a valid AWS
            region identifier (e.g., `us-east-1`, `eu-west-2`).
          example: us-east-1
        accountId:
          type: string
          description: |
            12-digit AWS account ID that owns the DynamoDB tables.
          example: '123456789012'
        roleArn:
          type: string
          description: >
            Full ARN of the IAM role to assume. The role must have a trust
            policy permitting DynamoSQL to assume it with the provided
            `externalId`. See the IAM Setup guide for the required trust policy
            and permission set.
          example: arn:aws:iam::123456789012:role/DynamoSQLReadRole
        externalId:
          type: string
          description: >
            External ID to include in `sts:AssumeRole`. Must match the
            `sts:ExternalId` condition in the role's trust policy. Generate a
            random string (UUID recommended) and store it in both DynamoSQL and
            your IAM role.
          example: dsql-ext-7f3a9c2b
        tableAllowlist:
          type: array
          items:
            type: string
          description: >
            Optional list of DynamoDB table names this schema may access. Omit
            to allow all tables visible to the role. Pass `["*"]` to explicitly
            allow all tables with wildcard validation. Individual names are
            matched exactly (case-sensitive).
          example:
            - Users
            - Orders
    ApiResponse:
      type: object
      required:
        - success
      properties:
        success:
          type: boolean
          description: >
            `true` when the request was processed without errors, `false`
            otherwise. Always present.
        data: {}
        error:
          $ref: '#/components/schemas/ApiError'
    Schema:
      type: object
      description: >
        A DynamoSQL schema record. A schema connects a logical name to the IAM
        role and AWS region DynamoSQL uses to access DynamoDB on your behalf via
        cross-account role assumption.
      required:
        - tenantId
        - schemaName
        - region
        - accountId
        - roleArn
        - externalId
        - status
        - createdAt
      properties:
        tenantId:
          type: string
          description: The tenant that owns this schema.
          example: tenant-abc123
        schemaName:
          type: string
          description: >
            The logical schema name used in SQL queries (e.g., `SELECT * FROM
            myschema.users`). Unique within a tenant. Case-insensitive at query
            time.
          example: myschema
        region:
          type: string
          description: |
            AWS region where the DynamoDB tables reside (e.g., `us-east-1`).
          example: us-east-1
        accountId:
          type: string
          description: 12-digit AWS account ID that owns the DynamoDB tables.
          example: '123456789012'
        roleArn:
          type: string
          description: >
            ARN of the IAM role DynamoSQL assumes to access DynamoDB. The role's
            trust policy must allow `sts:AssumeRole` from the DynamoSQL service
            account with the matching `externalId`.
          example: arn:aws:iam::123456789012:role/DynamoSQLReadRole
        externalId:
          type: string
          description: >
            External ID included in the `sts:AssumeRole` call. Must match the
            condition in the role's trust policy. Acts as a second factor to
            prevent confused-deputy attacks.
          example: dsql-ext-7f3a9c2b
        tableAllowlist:
          type: array
          items:
            type: string
          description: >
            Optional list of DynamoDB table names this schema is permitted to
            access. When omitted or empty, all tables visible to the role are
            accessible. Pass `["*"]` to explicitly allow all tables. Names are
            matched exactly (case-sensitive).
          example:
            - Users
            - Orders
            - Products
        status:
          type: string
          enum:
            - active
            - disabled
          description: >
            `active` — the schema is available for SQL queries and metadata
            refreshes. `disabled` — the schema is suspended; queries referencing
            it will fail until re-enabled.
          example: active
        createdAt:
          type: string
          format: date-time
          description: ISO 8601 timestamp when the schema was created.
          example: '2026-01-15T10:30:00.000Z'
        updatedAt:
          type: string
          format: date-time
          description: ISO 8601 timestamp of the last update, if any.
          example: '2026-02-20T14:45:00.000Z'
    ApiError:
      type: object
      description: Present in the response body when `success` is `false`.
      properties:
        message:
          type: string
          description: Human-readable description of what went wrong.
        code:
          type: string
          description: Machine-readable error code, when available.
        requestId:
          type: string
          description: |
            Request correlation ID. Include this when contacting support.
  responses:
    BadRequest:
      description: >
        Validation error — a required field is missing, a value is out of range,
        a date is malformed, or the request body is otherwise invalid. Check the
        `error.message` field for details.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ApiResponse'
          example:
            success: false
            error:
              message: startDate must be before or equal to endDate
    Unauthorized:
      description: >
        Missing `Authorization` header, expired JWT, or token issuer/audience
        does not match the DynamoSQL Cognito user pool.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ApiResponse'
          example:
            success: false
            error:
              message: Unauthorized
    Forbidden:
      description: >
        The caller lacks the required role or a tenant-scoping violation was
        detected.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ApiResponse'
          example:
            success: false
            error:
              message: Tenant admin access required
    Conflict:
      description: >
        A resource with the same unique key already exists (e.g., duplicate
        schema name).
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ApiResponse'
          example:
            success: false
            error:
              message: A schema with that name already exists
  securitySchemes:
    cognitoJwt:
      type: http
      scheme: bearer
      bearerFormat: JWT
      description: >
        Bearer token obtained from `POST /v1/auth/token`. Pass in the
        `Authorization` header as `Bearer <token>`.

````