PRODUCTS

KEYWORDS

Introducing the Hosted Dolt REST API

Hosted Dolt is for running online, production Dolt and Doltgres databases. You choose the server and disk you need, and we provision the resources and run the database for you, complete with logging, metrics, backups, and upgrades.

Up until now, the only way to create or manage one of those deployments was from the web UI. Today I’m happy to announce that Hosted Dolt has an official REST API. It’s live at https://hosted.doltdb.com/api/v1/, and it’s documented at dolthub.com/docs/products/hosted/api/v1.

If you’ve used the DoltHub API v2 we released last month, this one will look familiar because it’s purposely built on the same contract.

Motivation#

Hosted Dolt has had two programmatic surfaces for a while. Both are good at what they were designed for, but neither was designed specifically for managing deployments.

The first is your deployment’s SQL endpoint. That’s a live Dolt or Doltgres server, so anything Dolt can do, you can do over a normal MySQL or Postgres connection, including branches, merges, diffs, and the rest of the version control system tables and procedures. This is limited to the data within your database and can not be used to provision or manage the deployment itself.

The second is the GraphQL API behind the Hosted website. A little over a year ago we wrote a blog called “Hosted Dolt’s Hidden GraphQL API”, which walked through pulling the hostedToken cookie out of your browser dev tools and hand-writing GraphQL queries against it. That post opened with a warning that it wasn’t an official API and could change at any time. People used it anyway because it was the only programmatic option for managing deployments.

Creating and managing deployments and instances will always be available from the web UI. But we believe Dolt is the database for agents, and in the age of agents it because increasingly important to provide an API an agent can use. Branching and diffing let an agent work in isolation and have changes audited before they merge, and you’ve been able to connect an agent to a Hosted deployment over MCP since February. Giving it a documented REST API with real status codes and a stable error model means it can provision the database it works in too, so the whole loop, from creating a deployment to querying it to shutting it down when it’s done, is something an agent can run end to end.

Built on the DoltHub API v2#

When we built the DoltHub API v2, the goal was a contract-first API where an OpenAPI 3.1 spec is the source of truth and everything else is generated from it: the published docs, the TypeScript types, the runtime request validation, and the contract tests. Adding an endpoint means editing the spec first, and anything that doesn’t match the spec doesn’t build.

That worked well enough that we reused the whole thing for Hosted. openapi/v1.yaml is the contract, the generated types are checked in and verified against the spec in CI, request bodies are validated at runtime against the spec’s schemas, and a breaking change check runs on every pull request. Both specs are even gated by the same CI workflow, one matrix entry each, so the two APIs can’t drift in how we detect breakage.

More importantly, the parts you actually touch as a caller are the same:

  • One success envelope. Every 2xx body is { "data": ..., "meta": ... }. data is the resource or the array of resources, and meta is optional.
  • One error model. Every non-2xx response is an RFC 9457 problem document, with a stable code in SCREAMING_SNAKE_CASE that you can branch on instead of parsing English.
  • Cursor pagination. Where a list paginates, the response has a meta.next_page_token that you pass back as page_token.
  • Bearer auth. Authorization: Bearer <token>, 401 if the credential is missing or bad, 403 if it’s valid but not allowed.
  • snake_case everywhere, and an x-request-id on every response, including successful ones.

There’s one deliberate difference. On DoltHub, endpoints are public unless they opt in to auth, because public database reads are its baseline. On Hosted, every endpoint requires a token and has to opt out. Hosted’s control plane has nothing that’s anonymously readable, so we flipped the default.

What it covers#

There are eleven endpoints today, and they cover your deployments, the instances behind them, their backups and configuration, and the options you can create them with.

EndpointWhat it does
GET /api/v1/userThe authenticated user’s profile
GET /api/v1/deployment-optionsThe zones, instance types, and storage a deployment can be created with
POST /api/v1/deploymentsCreate a deployment
GET /api/v1/deployments/{owner}List an owner’s deployments
GET /api/v1/deployments/{owner}/{deployment}Get a deployment
POST /api/v1/deployments/{owner}/{deployment}/disableDisable a deployment
GET /api/v1/deployments/{owner}/{deployment}/instancesList the instances behind a deployment
POST /api/v1/deployments/{owner}/{deployment}/instancesAdd a read replica
DELETE /api/v1/deployments/{owner}/{deployment}/instances/{id}Remove an instance
GET /api/v1/deployments/{owner}/{deployment}/backupsList a deployment’s backups
GET /api/v1/deployments/{owner}/{deployment}/configGet a deployment’s database configuration

This API is the deployment control plane only. Querying the data inside a deployment isn’t part of this API and won’t be. Your deployment already exposes a SQL endpoint you connect to directly with your own database credentials, and that’s a much better interface for queries than anything we’d put over HTTP. For the same reason, your database credentials are deliberately not part of the deployment resource, so reading a deployment never hands out a credential.

Getting a token#

First you’ll need a token. Create one from the Tokens section of your user settings. Hosted API tokens are prefixed hsat.v1., they carry the same permissions as the user who created them, and they expire on a date you pick.

export HOSTED_TOKEN=hsat.v1.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

The quickest way to check it works is GET /api/v1/user. A 200 tells you the token is good and whose access it carries.

curl -s 'https://hosted.doltdb.com/api/v1/user' \
  -H "Authorization: Bearer $HOSTED_TOKEN"
{
  "data": {
    "username": "acme-ops",
    "display_name": "Acme Operations",
    "company": "Acme Corp",
    "email_addresses": [
      { "address": "ops@acme.com", "is_verified": true, "is_primary": true }
    ]
  }
}

Creating a deployment#

1. See what you can create#

GET /api/v1/deployment-options tells you the options you can use to create a deployment or instance. It narrows in steps, since each choice depends on the one before it. Pass cloud on its own to get its zones, add zone to also get that zone’s instance types, and add instance_type_id to also get the storage that works with that instance. Anything you haven’t narrowed enough to determine is left out rather than returned empty.

curl -s -G 'https://hosted.doltdb.com/api/v1/deployment-options' \
  -H "Authorization: Bearer $HOSTED_TOKEN" \
  -d cloud=aws \
  -d zone=us-east-1 \
  -d instance_type_id=aws.t2.medium
{
  "data": {
    "cloud": "aws",
    "zones": ["us-east-1"],
    "instance_types": [
      {
        "id": "aws.t2.medium",
        "name": "t2.medium",
        "cpus": 2,
        "memory_gb": 4,
        "description": "Trial tier, the lowest spec that runs a Dolt SQL server.",
        "hourly_cost_usd": 0.06849315
      }
    ],
    "storage_options": [
      {
        "id": "aws.ebs.gp3_50",
        "name": "Trial 50GB EBS",
        "description": "Trial tier storage capped at 50GB",
        "min_size_gb": 50,
        "max_size_gb": 50,
        "monthly_cost_usd_per_gb": 0
      }
    ]
  }
}

Note that you will need the id, not the name, for the create deployment endpoint.

2. Create it#

curl -s -X POST 'https://hosted.doltdb.com/api/v1/deployments' \
  -H 'Content-Type: application/json' \
  -H "Authorization: Bearer $HOSTED_TOKEN" \
  -d '{
    "owner": "acme",
    "name": "analytics",
    "cloud": "aws",
    "zone": "us-east-1",
    "instance_type_id": "aws.t2.medium",
    "volume_type_id": "aws.ebs.gp3_50",
    "volume_size_gb": 50
  }'

You get back a 202, meaning we’ve accepted the request and provisioning continues after the response. host is empty until the deployment comes up.

{
  "data": {
    "owner": "acme",
    "name": "analytics",
    "state": "starting",
    "cloud": "aws",
    "zone": "us-east-1",
    "cluster_type": "dolt",
    "instance_type_name": "t2.medium",
    "volume_type_name": "Trial 50GB EBS",
    "volume_size_gb": 50,
    "replicas": 0,
    "host": "",
    "port": 3306,
    "caller_role": "admin",
    "created_by": "acme-ops",
    "created_at": "2026-08-11T09:14:00Z"
  }
}

cluster_type defaults to dolt. Pass doltgres if you want a Doltgres deployment, or mysql_with_dolt_replicas for a MySQL primary with Dolt read replicas.

3. Wait for it to start#

The DoltHub API v2 routes its async work through a single Operation resource that you poll. We didn’t need one here, because the deployment is already the thing whose state you care about. So you poll the deployment until state is started.

curl -s 'https://hosted.doltdb.com/api/v1/deployments/acme/analytics' \
  -H "Authorization: Bearer $HOSTED_TOKEN"
{
  "data": {
    "owner": "acme",
    "name": "analytics",
    "state": "started",
    "cloud": "aws",
    "zone": "us-east-1",
    "cluster_type": "dolt",
    "instance_type_name": "t2.medium",
    "volume_type_name": "Trial 50GB EBS",
    "volume_size_gb": 50,
    "replicas": 0,
    "database_version": "1.58.4",
    "host": "analytics.dbs.hosted.doltdb.com",
    "port": 3306,
    "hourly_cost_usd": 0.06849315,
    "webpki_cert": true,
    "expose_remotesapi_endpoint": false,
    "expose_mcp": false,
    "expose_stats": false,
    "disable_automatic_dolt_updates": false,
    "caller_role": "admin",
    "created_by": "acme-ops",
    "created_at": "2026-07-01T18:22:04Z"
  }
}

host and port are your connection details, and from here you’re in normal Dolt territory.

mysql -h analytics.dbs.hosted.doltdb.com -P 3306 -u <user> -p

The same starting to started transition covers restarts and resizes too, so the same poll works for those.

Inspecting a deployment#

GET /api/v1/deployments/{owner} lists deployments for an owner name. It takes an optional state filter and it paginates. The items are a summary rather than the full deployment, so it drops the connection details and adds last backup information.

curl -s -G 'https://hosted.doltdb.com/api/v1/deployments/acme' \
  -H "Authorization: Bearer $HOSTED_TOKEN" \
  -d state=started
{
  "data": [
    {
      "owner": "acme",
      "name": "analytics",
      "state": "started",
      "cloud": "aws",
      "zone": "us-west-2",
      "cluster_type": "dolt",
      "instance_type_name": "m5.large",
      "volume_type_name": "gp3",
      "volume_size_gb": 100,
      "replicas": 0,
      "database_version": "1.58.4",
      "hourly_cost_usd": 0.192,
      "webpki_cert": true,
      "last_backup_time": "2026-08-10T02:00:00Z",
      "last_backup_size_bytes": 1048576
    }
  ],
  "meta": {
    "next_page_token": "eyJvZmZzZXQiOjI1fQ"
  }
}

Pass the next_page_token back as page_token for the next page, and stop when meta isn’t there anymore.

You can list the backups we’re holding for a deployment, newest first:

curl -s 'https://hosted.doltdb.com/api/v1/deployments/acme/analytics/backups' \
  -H "Authorization: Bearer $HOSTED_TOKEN"
{
  "data": [
    {
      "id": "20260812T020000.000",
      "databases": ["analytics", "staging"],
      "instance_index": 0,
      "created_at": "2026-08-12T02:00:00Z"
    },
    {
      "id": "20260811T020000.000",
      "databases": ["analytics", "staging"],
      "size_bytes": 1048576,
      "instance_index": 0,
      "created_at": "2026-08-11T02:00:00Z"
    }
  ]
}

The newest backup there doesn’t have a size_bytes yet. That’s expected, since we measure it asynchronously after the backup is taken, so a recent one has no size for a few minutes.

And you can read a deployment’s database configuration. This returns every setting Hosted supports, at the value the deployment is actually running, which is the same thing the Configuration page in the UI shows you. is_overridden tells you whether you changed it, and default tells you what it would go back to.

curl -s 'https://hosted.doltdb.com/api/v1/deployments/acme/analytics/config' \
  -H "Authorization: Bearer $HOSTED_TOKEN"
{
  "data": {
    "settings": [
      {
        "key": "listener_max_connections",
        "value": "500",
        "default": "100",
        "is_overridden": true
      },
      {
        "key": "behavior_read_only",
        "value": "false",
        "default": "false",
        "is_overridden": false
      }
    ]
  }
}

Values come back as strings exactly as they’re stored, including the numeric and boolean ones.

Disabling a deployment#

POST .../disable tears a deployment’s instances and storage down. You get a 202 with the deployment in stopping, and you poll the deployment until it’s stopped.

curl -s -X POST 'https://hosted.doltdb.com/api/v1/deployments/acme/analytics/disable' \
  -H "Authorization: Bearer $HOSTED_TOKEN"
{
  "data": {
    "owner": "acme",
    "name": "analytics",
    "state": "stopping"
  }
}

Take a backup first if you want the data.

The deployment record itself sticks around. It stays readable with disabled_at and disabled_by set, which is why this is a POST to an action rather than a DELETE on the deployment. To bring it back, add an instance to it, which clears the shutdown and starts it up again. Pass a backup_id from the backups list on that request to restore your data into it, or it’ll come back empty.

Documentation#

The full reference lives at dolthub.com/docs/products/hosted/api/v1. Every endpoint, schema, error code, and security scheme there is rendered straight from the OpenAPI spec, so there’s no drift between what the docs say and what the server does.

If you’d rather generate a typed client in your language of choice, the spec itself is in our docs repo. Grab it and point your generator at it.

Future work#

v1 is additive. We can add endpoints, optional request fields, response fields, and new error codes within v1, and we’d only need a v2 to rename or remove a field or change what an existing one means. So you can build against what’s live today without worrying that the rest of it will move underneath you.

There’s more coming:

  • Pull requests: creating, viewing, and merging them. Every other version control operation is available over SQL on your deployment, but pull request metadata lives in Hosted’s application database rather than in your Dolt database, so there’s no query that opens or manages one.
  • Credentials: issuing and rotating a deployment’s database credentials.
  • Configuration writes: updating deployment settings and Dolt configuration.
  • Deployment actions: upgrading Dolt/Doltgres, rebooting an instance, and restarting an application.
  • Access management: adding and removing collaborators and their roles.
  • CLIs: we’re building a command line tool on top of this API and the DoltHub API v2, along the lines of GitHub’s gh, so you can drive either product from your terminal without writing the HTTP calls yourself.

Conclusion#

Between this and the DoltHub API v2, building against either of our products should feel like working with the same API. If it doesn’t somewhere, that’s a bug and we want to hear about it.

Create a token and try it out. File an issue if there’s an endpoint you want sooner or is not covered above, or come to talk to us on Discord.