
## Quick start

Get the schema JSON for any of your diagrams in three requests: create a token, find the diagram's `uuid`, read its schema. You need a team on a paid plan.

### 1. Create a token

Go to [Account → API tokens](/user/api-tokens), pick the team you want to read from, and create a token. The token is shown once. Copy it into an environment variable so the rest of these commands paste as-is:

```bash
export DRAWSQL_TOKEN="<your-token>"
```

### 2. Find a diagram

List the diagrams your token can see. Every diagram has a `uuid`, which is how the rest of the API refers to it.

```bash
curl https://api.drawsql.app/v1/diagrams \
  -H "Authorization: Bearer $DRAWSQL_TOKEN"
```

```json
{
  "data": [
    {
      "uuid": "ee49b61f-5425-4013-ade7-3c83fd43be3f",
      "name": "Orders service",
      "table_count": 12
    }
  ]
}
```

### 3. Read its schema

Take a `uuid` from that response and ask for the schema. Piping through `jq` shows you the table names straight away:

```bash
curl https://api.drawsql.app/v1/diagrams/ee49b61f-5425-4013-ade7-3c83fd43be3f/schema \
  -H "Authorization: Bearer $DRAWSQL_TOKEN" | jq '.data.tables[].name'
```

```text
"orders"
"order_items"
"users"
```

Everything below is the contract in detail: response shapes, pagination, caching, rate limits, and errors.

## Authentication

Every request needs a personal access token. You may create one under [Account → API tokens](/user/api-tokens). Each token belongs to one team and can read the diagrams you can already see in that team, so there is nothing extra to configure. You may choose an expiry of 30 days, 90 days, 1 year, or 2 years; if you are unsure, the default of 1 year is a sensible choice. The token stops working if you leave the team or the team's plan lapses.

```bash
curl https://api.drawsql.app/v1/diagrams \
  -H "Authorization: Bearer <your-token>"
```

Session cookies are not supported. Send the token as a bearer token on every request. Treat it like a password: anyone with it can read your team's diagrams. Of course, you may revoke a token at any time from the same settings page.

## Base URL & responses

```text
https://api.drawsql.app/v1
```

Responses with a body use JSON. Successful responses use a top-level `data` field; errors use a top-level `error` field. We may add fields within v1, so ignore unknown fields. Don't worry about your integration breaking: we will not rename or remove an existing field without shipping a new version (`/v2`) and giving at least six months' notice.

## List diagrams

<div class="endpoint-row"><span class="method-tag method-get">GET</span><code>/diagrams</code></div>

Returns the diagrams the token can access, ordered by `updated_at`, newest first.

```json
{
  "data": [
    {
      "uuid": "ee49b61f-5425-4013-ade7-3c83fd43be3f",
      "name": "Orders service",
      "slug": "orders-service",
      "description": null,
      "team": { "name": "Acme", "slug": "acme" },
      "table_count": 12,
      "url": "https://drawsql.app/teams/acme/diagrams/orders-service",
      "embed_url": "https://drawsql.app/teams/acme/diagrams/orders-service/embed",
      "updated_at": "2026-07-01T09:14:02+00:00"
    }
  ],
  "meta": { "next_cursor": null, "has_more": false }
}
```

## Get a diagram

<div class="endpoint-row"><span class="method-tag method-get">GET</span><code>/diagrams/{uuid}</code></div>

Returns metadata for one diagram in `data`, the same shape as a list item.

Unknown, malformed, and unauthorized UUIDs all return the same `404`, so the API never reveals whether a diagram you can't see exists.

## Get a diagram's schema

<div class="endpoint-row"><span class="method-tag method-get">GET</span><code>/diagrams/{uuid}/schema</code></div>

Returns tables, columns, indexes, and relationships. Canvas layout, groups, and sticky notes are omitted. Use `/schema-full` when you need a re-importable DrawSQL document.

```json
{
  "data": {
    "driver": "pgsql",
    "schema_version": 3.1,
    "tables": [
      {
        "uuid": "<table-uuid>",
        "name": "users",
        "comment": null,
        "columns": [
          {
            "uuid": "<column-uuid>",
            "name": "id",
            "driver_data_type_name": "bigint",
            "driver_data_type_params": null,
            "default": null,
            "is_nullable": false,
            "is_primary_key": true,
            "is_unique_key": false,
            "is_index": false,
            "is_auto_increment": true,
            "is_unsigned": false,
            "comment": null
          }
        ],
        "indexes": []
      }
    ],
    "relationships": []
  }
}
```

Tables are sorted by name. Columns and indexes keep their schema order. Columns identify their type by `driver_data_type_name`, such as `bigint`.

This endpoint serves JSON only. An `Accept` header that excludes JSON, or a `?format=` value other than `json`, returns a `406`.

## Get the full diagram document

<div class="endpoint-row"><span class="method-tag method-get">GET</span><code>/diagrams/{uuid}/schema-full</code></div>

Returns the full diagram document: the same table, column, index, and relationship fields as `/schema`, plus canvas positions, colors, group membership, groups, and sticky notes.

Only security-sensitive persistence fields are removed. The complete response shape is in the [API reference](/developers/api/reference).

## Pagination

`GET /diagrams` is cursor-paginated. You may pass `?limit=` (1–100; the default is 25). When `meta.has_more` is true, pass `meta.next_cursor` back as `?cursor=` to fetch the next page.

```bash
curl "https://api.drawsql.app/v1/diagrams?limit=50&cursor=<next-cursor>" \
  -H "Authorization: Bearer <your-token>"
```

## Conditional requests

Both schema endpoints return an `ETag`. You may send it back as `If-None-Match`; if the response has not changed, you get a `304 Not Modified` with no body.

```bash
curl -i "https://api.drawsql.app/v1/diagrams/<uuid>/schema" \
  -H "Authorization: Bearer <your-token>" \
  -H 'If-None-Match: "19b90083562ef66e0e0d9562fc4f4abbb8740b54"'
# → HTTP/1.1 304 Not Modified
```

| Endpoint | ETag changes when |
| --- | --- |
| `/schema` | The schema content changes, including table or column comments. Canvas-only edits, such as moving or recoloring a table, still return `304`. |
| `/schema-full` | Any schema or canvas edit represented in the full document. |

## Rate limits

| Operation | Limit |
| --- | --- |
| Listing and reading a diagram | 60 / minute, per token |
| Reading `/schema` or `/schema-full` | 30 / minute, per token |
| Any request | 60 / minute, per IP |

Authenticated requests get `X-RateLimit-Limit` and `X-RateLimit-Remaining` response headers for the token limit that applies. Requests over a limit return a `429` with a `Retry-After` header that says how many seconds to wait.

## Errors

Errors use a consistent shape with a stable, machine-readable code:

```json
{ "error": { "code": "plan_required", "message": "The public API requires a paid plan. Upgrade this token's team to restore access." } }
```

| Status | Code | Meaning |
| --- | --- | --- |
| `401` | `unauthenticated` | The token is missing, expired, or revoked. |
| `401` | `invalid_token` | The token's team no longer exists, or you're no longer a member of it. |
| `403` | `forbidden` | The token is not allowed to perform this action. |
| `403` | `plan_required` | The token's team isn't on a paid plan. |
| `404` | `not_found` | No such diagram, or it isn't visible to your token. |
| `406` | `not_acceptable` | A non-JSON schema format was requested. |
| `422` | `invalid_request` | A query parameter failed validation. |
| `429` | `rate_limited` | Too many requests. |
| Other `4xx` | `request_failed` | Any other client error, such as an unsupported method. |

## OpenAPI

The full contract is published as an OpenAPI 3.1 document at [drawsql.app/openapi.yaml](/openapi.yaml), rendered as an interactive [API reference](/developers/api/reference). You may point a client generator at the spec to get typed models.
