REST API
The ready.dev API lets you manage your infrastructure programmatically. All endpoints return JSON and use standard HTTP methods.
https://cloud.ready.dev/apiAuthentication
Authenticate requests by including your API key in the Authorization header. API keys are cluster-scoped and can optionally be restricted to specific projects or domains. Manage keys from your cluster settings.
Keep your keys safe
Authorization: Bearer your_api_key_hereCluster
Retrieve information about the cluster associated with your API key.
/clusterGet cluster details.
curl https://cloud.ready.dev/api/cluster \
-H "Authorization: Bearer your_api_key_here"{
"cluster": {
"name": "production",
"project_count": 3,
"resource_count": 12,
"status": "active"
}
}Projects
Projects are logical groupings of resources within a cluster. Resource names must be unique within a project.
/projectsList all projects you have access to.
curl https://cloud.ready.dev/api/projects \
-H "Authorization: Bearer your_api_key_here"{
"projects": [
{
"name": "my-saas-app",
"description": "Production SaaS application",
"resource_count": 3,
"created_at": "2026-01-10T08:00:00Z",
"updated_at": "2026-01-15T12:00:00Z"
}
]
}/projects/:nameRetrieve details for a specific project, including its resources.
{
"project": {
"name": "my-saas-app",
"description": "Production SaaS application",
"resource_count": 2,
"created_at": "2026-01-10T08:00:00Z",
"updated_at": "2026-01-15T12:00:00Z",
"resources": [
{
"name": "web",
"resource_type": "github",
"state": "active",
"deployment_hash": "abc123",
"hosts": ["host-1"]
}
]
}
}/projectsCreate a new project.
| Parameter | Description |
|---|---|
| project[name] | (required) Project name |
| project[description] | Project description |
curl -X POST https://cloud.ready.dev/api/projects \
-H "Authorization: Bearer your_api_key_here" \
-H "Content-Type: application/json" \
-d '{"project": {"name": "my-saas-app", "description": "Production SaaS application"}}'{
"project": {
"name": "my-saas-app",
"description": "Production SaaS application",
"resource_count": 0,
"created_at": "2026-01-10T08:00:00Z",
"updated_at": "2026-01-10T08:00:00Z"
}
}/projects/:nameCreate or update a project. Creates if the project doesn't exist, updates if it does.
| Parameter | Description |
|---|---|
| description | Project description |
curl -X PUT https://cloud.ready.dev/api/projects/my-saas-app \
-H "Authorization: Bearer your_api_key_here" \
-H "Content-Type: application/json" \
-d '{"description": "Updated description"}'{
"project": {
"name": "my-saas-app",
"description": "Updated description",
"resource_count": 2,
"created_at": "2026-01-10T08:00:00Z",
"updated_at": "2026-02-01T09:30:00Z"
}
}/projects/:nameDelete a project. The project must have no resources.
{
"status": "deleted",
"project": "my-saas-app"
}Resources
Resources are deployable units within a project — a GitHub repo, Docker container, managed database, or manual instance. Each resource runs on one or more hosts in your cluster.
/resources/:projectList all resources in a project.
curl https://cloud.ready.dev/api/resources/my-saas-app \
-H "Authorization: Bearer your_api_key_here"{
"project": "my-saas-app",
"resources": [
{
"name": "web",
"state": "active",
"resource_type": "github",
"deployment_hash": "abc123",
"instance_config": {
"cpu": 2,
"memory": 4.0,
"storage": 20.0,
"github_repo_url": "https://github.com/acme/web.git",
"branch_name": "main"
},
"created_at": "2026-01-15T10:30:00Z",
"updated_at": "2026-02-20T14:00:00Z",
"project": "my-saas-app",
"hosts": ["host-1"],
"health_checks": [
{
"check_type": "http",
"target": "/health",
"port": 3000,
"expected_status_code": 200,
"expected_text": null,
"timeout": 5,
"status": "healthy",
"last_checked_at": "2026-02-24T14:20:00Z"
}
],
"domains": [
{
"domain": "example.com",
"subdomain": "app",
"internal_port": 3000
}
]
}
]
}/resources/:project/:nameRetrieve details for a specific resource.
{
"resource": {
"name": "web",
"state": "active",
"resource_type": "github",
"deployment_hash": "abc123",
"instance_config": {
"cpu": 2,
"memory": 4.0,
"storage": 20.0,
"github_repo_url": "https://github.com/acme/web.git",
"branch_name": "main"
},
"created_at": "2026-01-15T10:30:00Z",
"updated_at": "2026-02-20T14:00:00Z",
"project": "my-saas-app",
"hosts": ["host-1"],
"health_checks": [],
"domains": []
}
}/resources/:project/:nameCreate or update a resource. Automatically triggers a deployment. If the project doesn't exist, it will be created.
| Parameter | Description |
|---|---|
| resource[resource_type] | (required) One of: github, dockerfile, manual, mysql, postgres, clickhouse |
| resource[state] | Resource state |
| resource[hosts] | Host names to deploy on (defaults to first host) |
| resource[instance_config] | Instance configuration (see below) |
| resource[domains] | Domain routing configuration |
| resource[health_checks_attributes] | Health check configuration |
The instance_config object supports the following fields depending on resource type:
| Field | Description |
|---|---|
| cpu | CPU cores (integer) |
| memory | Memory in GB (float) |
| storage | Storage in GB (float) |
| github_repo_url | GitHub repository URL (for github type) |
| branch_name | Branch to deploy (for github type) |
| project_folder | Subfolder in repo (for github type) |
| base_image | Base image name (for github type) |
| dockerfile_content | Inline Dockerfile (for dockerfile type) |
| docker_image | Docker Hub image (for dockerfile type) |
| docker_tag | Docker tag (for dockerfile type) |
| registry_username | Private registry username |
| registry_password | Private registry password |
| env_vars | Environment variables: [{"key": "...", "value": "...", "include_in_build": true}] |
| exposed_ports | Ports to expose: [3000, 8080] |
| injected_files | Files to inject: [{"path": "...", "content": "...", "location": "..."}] |
| persistent_volumes | Persistent volume paths |
curl -X PUT https://cloud.ready.dev/api/resources/my-saas-app/web \
-H "Authorization: Bearer your_api_key_here" \
-H "Content-Type: application/json" \
-d '{
"resource": {
"resource_type": "github",
"instance_config": {
"cpu": 2,
"memory": 4.0,
"storage": 20.0,
"github_repo_url": "https://github.com/acme/web.git",
"branch_name": "main",
"base_image": "ruby",
"env_vars": [
{"key": "RAILS_ENV", "value": "production", "include_in_build": false}
]
},
"domains": [
{
"subdomain": "app",
"domain": "example.com",
"port": 3000
}
]
}
}'{
"status": "created",
"resource": {
"name": "web",
"state": "active",
"resource_type": "github",
"deployment_hash": "def456",
"instance_config": {
"cpu": 2,
"memory": 4.0,
"storage": 20.0,
"github_repo_url": "https://github.com/acme/web.git",
"branch_name": "main",
"base_image": "ruby",
"env_vars": [
{"key": "RAILS_ENV", "value": "production", "include_in_build": false}
]
},
"created_at": "2026-02-24T14:22:00Z",
"updated_at": "2026-02-24T14:22:00Z",
"project": "my-saas-app",
"hosts": ["host-1"],
"health_checks": [],
"domains": [
{
"domain": "example.com",
"subdomain": "app",
"internal_port": 3000
}
]
}
}/resources/:project/:name/cloneClone an existing resource. Only allows upsizing — CPU, memory, and storage cannot be decreased.
| Parameter | Description |
|---|---|
| resource[name] | (required) Name for the cloned resource |
| resource[clone_data] | Clone data as well (for databases) |
| resource[state] | Override state on the clone |
| resource[hosts] | Override hosts on the clone |
| resource[instance_config] | Override cpu, memory, storage (upsizing only) |
curl -X POST https://cloud.ready.dev/api/resources/my-saas-app/web/clone \
-H "Authorization: Bearer your_api_key_here" \
-H "Content-Type: application/json" \
-d '{
"resource": {
"name": "web-staging",
"instance_config": {
"cpu": 4,
"memory": 8.0
}
}
}'{
"status": "cloned",
"resource": {
"name": "web-staging",
"state": "active",
"resource_type": "github",
"deployment_hash": "ghi789",
"instance_config": {
"cpu": 4,
"memory": 8.0,
"storage": 20.0
},
"created_at": "2026-02-24T15:00:00Z",
"updated_at": "2026-02-24T15:00:00Z",
"project": "my-saas-app",
"hosts": ["host-1"],
"health_checks": [],
"domains": []
}
}/resources/:project/:nameDelete a resource.
{
"status": "deleted",
"project": "my-saas-app",
"resource": "web"
}Deploys
Check the status of a specific deployment by its hash. Deploys are triggered automatically when you create or update a resource.
/resources/:project/:name/deploys/:hashGet the status of a deployment.
curl https://cloud.ready.dev/api/resources/my-saas-app/web/deploys/abc123 \
-H "Authorization: Bearer your_api_key_here"{
"status": "completed",
"started_at": "2026-02-24T14:22:00Z",
"completed_at": "2026-02-24T14:23:15Z",
"log": "Building image...\nDeploying to host-1...\nDeploy complete."
}Domains
Domains let you serve resources on custom hostnames. These endpoints require an API key with the manage_domains permission. The domain_type is set once at creation and cannot be changed afterwards — valid types are public_https_proxy, private_https_proxy, private_dns_only, and cloudflare_managed. Cloudflare-managed domains require a zone_id and are configured through Cloudflare, so they are read-only via the API.
DNS verification runs asynchronously after a domain is created. Poll the domain's dns_verified and ssl_status fields to track progress. Domains whose DNS you manage yourself (dns_managed_externally: true) must point an _acme-challenge CNAME at your cluster before verification can succeed.
/domainsList all domains you have access to.
curl https://cloud.ready.dev/api/domains \
-H "Authorization: Bearer your_api_key_here"{
"domains": [
{
"domain_name": "app.example.com",
"domain_type": "public_https_proxy",
"dns_managed_externally": false,
"dns_verified": true,
"dns_verified_at": "2026-02-20T14:00:00Z",
"ssl_status": "issued",
"zone_id": null,
"account_id": null,
"dns_records": [
{"record_type": "A", "name": "@", "content": "192.0.2.1"},
{"record_type": "TXT", "name": "@", "content": "v=spf1 include:_spf.example.com ~all"}
],
"resource_count": 2,
"created_at": "2026-01-15T10:30:00Z",
"updated_at": "2026-02-20T14:00:00Z"
}
]
}/domains/:domain_nameRetrieve details for a specific domain.
{
"domain": {
"domain_name": "app.example.com",
"domain_type": "public_https_proxy",
"dns_managed_externally": false,
"dns_verified": true,
"dns_verified_at": "2026-02-20T14:00:00Z",
"ssl_status": "issued",
"zone_id": null,
"account_id": null,
"dns_records": [],
"resource_count": 2,
"created_at": "2026-01-15T10:30:00Z",
"updated_at": "2026-02-20T14:00:00Z"
}
}/domainsCreate a new domain.
| Parameter | Description |
|---|---|
| domain[domain_name] | (required) The custom hostname, e.g. app.example.com |
| domain[domain_type] | (required) One of: public_https_proxy, private_https_proxy, private_dns_only, cloudflare_managed. Immutable after creation. |
| domain[zone_id] | Cloudflare zone ID (required for cloudflare_managed) |
| domain[account_id] | Cloudflare account ID |
| domain[dns_managed_externally] | Set true if you manage DNS yourself via an _acme-challenge CNAME |
| domain[dns_records] | Array of DNS records: [{"record_type": "A", "name": "@", "content": "192.0.2.1"}] |
curl -X POST https://cloud.ready.dev/api/domains \
-H "Authorization: Bearer your_api_key_here" \
-H "Content-Type: application/json" \
-d '{
"domain": {
"domain_name": "app.example.com",
"domain_type": "public_https_proxy"
}
}'{
"domain": {
"domain_name": "app.example.com",
"domain_type": "public_https_proxy",
"dns_managed_externally": false,
"dns_verified": false,
"dns_verified_at": null,
"ssl_status": "pending",
"zone_id": null,
"account_id": null,
"dns_records": [],
"resource_count": 0,
"created_at": "2026-02-24T14:22:00Z",
"updated_at": "2026-02-24T14:22:00Z"
}
}/domains/:domain_nameCreate or update a domain. Creates if the domain doesn't exist, updates if it does. The domain name comes from the URL, and domain_type is only honored on create.
| Parameter | Description |
|---|---|
| domain[domain_type] | Only applied when creating a new domain; ignored on update |
| domain[zone_id] | Cloudflare zone ID |
| domain[account_id] | Cloudflare account ID |
| domain[dns_managed_externally] | Whether you manage DNS yourself |
| domain[dns_records] | Array of DNS records |
curl -X PUT https://cloud.ready.dev/api/domains/app.example.com \
-H "Authorization: Bearer your_api_key_here" \
-H "Content-Type: application/json" \
-d '{
"domain": {
"dns_managed_externally": true
}
}'{
"domain": {
"domain_name": "app.example.com",
"domain_type": "public_https_proxy",
"dns_managed_externally": true,
"dns_verified": true,
"dns_verified_at": "2026-02-20T14:00:00Z",
"ssl_status": "issued",
"zone_id": null,
"account_id": null,
"dns_records": [],
"resource_count": 2,
"created_at": "2026-01-15T10:30:00Z",
"updated_at": "2026-02-24T15:00:00Z"
}
}/domains/:domain_nameDelete a domain. Cloudflare-managed domains cannot be deleted via the API.
{
"status": "deleted",
"domain": "app.example.com"
}Errors
The API uses standard HTTP status codes. Error responses include a JSON body with error and message fields.
{
"error": "Not found",
"message": "Project 'nonexistent' not found"
}| Status | Meaning |
|---|---|
| 401 | Missing or invalid API key |
| 403 | API key lacks required permission or project access |
| 404 | Project or resource not found |
| 409 | Conflict (e.g. duplicate domain configuration) |
| 422 | Validation error (e.g. deleting a project that has resources) |
| 429 | Rate limited — back off and retry after a delay |
Examples
curl -X PUT https://cloud.ready.dev/api/resources/my-project/web \
-H "Authorization: Bearer your_api_key_here" \
-H "Content-Type: application/json" \
-d '{
"resource": {
"resource_type": "github",
"instance_config": {
"cpu": 2,
"memory": 4.0,
"storage": 20.0,
"github_repo_url": "https://github.com/acme/web.git",
"branch_name": "main",
"base_image": "ruby",
"exposed_ports": [3000],
"env_vars": [
{"key": "RAILS_ENV", "value": "production"}
]
},
"domains": [
{"subdomain": "app", "domain": "example.com", "port": 3000}
]
}
}'curl -X PUT https://cloud.ready.dev/api/resources/my-project/db \
-H "Authorization: Bearer your_api_key_here" \
-H "Content-Type: application/json" \
-d '{
"resource": {
"resource_type": "mysql",
"instance_config": {
"cpu": 2,
"memory": 4.0,
"storage": 50.0,
"mysql_username": "app",
"mysql_password": "secret",
"default_database": "myapp_production"
}
}
}'curl -X PUT https://cloud.ready.dev/api/resources/my-project/bastion \
-H "Authorization: Bearer your_api_key_here" \
-H "Content-Type: application/json" \
-d '{
"resource": {
"resource_type": "manual",
"instance_config": {
"cpu": 1,
"memory": 1.0,
"storage": 10.0,
"ssh_keys": "ssh-ed25519 AAAAC3Nza... user@host"
}
}
}'curl -X PUT https://cloud.ready.dev/api/resources/my-project/web \
-H "Authorization: Bearer your_api_key_here" \
-H "Content-Type: application/json" \
-d '{"resource": {"deploy": true}}'