Servers

Servers are the foundation of your deployment infrastructure. They represent the remote machines where your projects are deployed and run. On this page, we will dive into the different server endpoints you can use to manage servers programmatically.

AUTH Authorization: Bearer {API_KEY} Create a token →

The server model #

The server model contains all the information about your servers, including their network configuration and connection details.

Properties #

id integer

Unique identifier for the server.

server_type integer

The type of server. 0 = App Server, 1 = Database Server, 2 = Cache Server, 3 = Meilisearch Server, 4 = Load Balancer.

environment string

Optional environment tag. One of production, staging, dev, or null for untagged.

is_pinned boolean

Whether the current user has pinned this server in their sidebar. Per-user value; another user’s pin state does not affect yours.

name string

The display name for the server.

public_ip string

The public IP address of the server.

private_ip string

The private IP address of the server.

ssh_port integer

The SSH port used to connect to the server.

nat_port integer

The NAT port used to connect to the server. Default is 22.

timezone string

The timezone of the server.

operating_system string

The operating system of the server.

connection_status integer

The connection status of the server. 0 = Disconnected, 1 = Connected.

server_status integer

The status of the server. 0 = Installing, 1 = Provisioning, 10 = Provisioned.

notes string

Any additional notes about the server.

queue_limit integer

The maximum number of projects at the same time that can be deployed to the server.

monitoring_enabled boolean

Whether monitoring is enabled for the server.

projects_count integer

The number of projects deployed to the server.

created_at timestamp

Timestamp of when the server was created.

updated_at timestamp

Timestamp of when the server was last updated.


POST/api/v1/servers

Create a server #

Order a server from a connected provider, or register a machine you already have.

Which fields apply depends on provider_type. Ordering from a provider also needs provider_id — the id of a connection from Configuration → Server Providers — and Depfloy checks the configuration against the provider before anything is billed, so a size that is not sold in the region you asked for comes back as a 422 rather than as a failed server.

Provider orders answer 202. The server row already exists and comes back as server_id; the machine is built in the background. Poll the retrieve endpoint until server_status reaches 10.

Attributes #

server_os string

Required. One of ubuntu_26_04, ubuntu_24_04, ubuntu_22_04. On a provider order this also decides the image — there is no image or AMI field to send.

provider_type string

hetzner, aws, digitalocean or custom. Treated as custom when omitted.

provider_id integer

Required for hetzner, aws and digitalocean. The connection to order through; it has to belong to your organization and match the provider type.

name string

Display name. Generated for you if you leave it out.

server_type integer

0 = App, 1 = Database, 2 = Cache, 3 = Meilisearch, 4 = Load Balancer. Defaults to 0.

public_ip string

Required when provider_type is custom, and has to be an address no other server uses. Provider orders fill it in themselves once the machine has an address.

Hetzner attributes #

hetzner_location string
A location name, such as nbg1.
hetzner_server_type string
A server type name, such as cx22.
hetzner_network string
Optional private network id.

AWS attributes #

aws_region string
Required. Region code, such as eu-central-1.
aws_instance_type string
Required. Instance type, such as t3.small.
aws_subnet_id string

Required. A subnet id from the networks the provider options endpoint returns for that region; it decides the availability zone.

aws_volume_size integer

Required, and at least 20. Root volume in GB. There is no default on this endpoint — the Console and an AI assistant both send 30, but a call that leaves it out is rejected.

aws_volume_type string
gp3, gp2 or io2. Defaults to gp3.
aws_use_elastic_ip boolean
Allocate and attach an Elastic IP. On unless you send false.

DigitalOcean attributes #

digitalocean_region string
Required. Region slug, such as fra1.
digitalocean_size string
Required. Droplet size slug, such as s-2vcpu-4gb.
digitalocean_vpc_uuid string

Optional. Leave it out and the droplet joins the region’s default VPC. A VPC belonging to another region is rejected.

digitalocean_use_firewall boolean

Put a Cloud Firewall in front of the droplet — inbound 22, 80 and 443, all outbound. On unless you send false.

digitalocean_use_reserved_ip boolean

Attach a Reserved IP and manage the server by that address. Off unless you send true.

One server on the Starter plan. Creating a second one is refused with a message telling you to upgrade, whichever provider it would have been on.

POST /api/v1/servers Request
DigitalOcean
curl https://app.depfloy.com/api/v1/servers \
  -H "Authorization: Bearer {API_KEY}" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "acme-app-1",
    "server_os": "ubuntu_24_04",
    "provider_type": "digitalocean",
    "provider_id": 3,
    "digitalocean_region": "fra1",
    "digitalocean_size": "s-2vcpu-4gb",
    "digitalocean_use_firewall": true,
    "digitalocean_use_reserved_ip": false
  }'
AWS
curl https://app.depfloy.com/api/v1/servers \
  -H "Authorization: Bearer {API_KEY}" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "acme-app-1",
    "server_os": "ubuntu_24_04",
    "provider_type": "aws",
    "provider_id": 2,
    "aws_region": "eu-central-1",
    "aws_instance_type": "t3.small",
    "aws_subnet_id": "subnet-0abc1234def567890",
    "aws_volume_size": 30,
    "aws_volume_type": "gp3",
    "aws_use_elastic_ip": true
  }'
Hetzner
curl https://app.depfloy.com/api/v1/servers \
  -H "Authorization: Bearer {API_KEY}" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "acme-app-1",
    "server_os": "ubuntu_24_04",
    "provider_type": "hetzner",
    "provider_id": 1,
    "hetzner_location": "nbg1",
    "hetzner_server_type": "cx22"
  }'
Your own machine
curl https://app.depfloy.com/api/v1/servers \
  -H "Authorization: Bearer {API_KEY}" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "rack-01",
    "server_os": "ubuntu_24_04",
    "provider_type": "custom",
    "public_ip": "203.0.113.10"
  }'
Response
{
    "status": "provisioning",
    "message": "Server creation started. You will receive real-time updates.",
    "server_id": 42
}
Rejected
{
    "status": "error",
    "message": "The selected VPC is not available in fra1. Choose a VPC in that region, or leave it empty to use the default one.",
    "errors": {
        "digitalocean_vpc_uuid": "The selected VPC is not available in fra1. Choose a VPC in that region, or leave it empty to use the default one."
    }
}

GET/api/v1/servers

List all servers #

This endpoint allows you to retrieve a paginated list of all your servers.

GET /api/v1/servers Request
cURL
curl -G https://app.depfloy.com/api/v1/servers \
  -H "Authorization: Bearer {API_KEY}" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json"
Response
{
    "current_page": 1,
    "data": [
        {
            "id": 48390,
            "server_type": 0,
            "name": "andreo-galaxy",
            "ssh_port": 22,
            "nat_port": null,
            "public_ip": "142.131.127.100",
            "private_ip": null,
            "timezone": "Europe/Istanbul",
            "operating_system": null,
            "connection_status": 1,
            "server_status": 10,
            "notes": null,
            "created_at": "2025-12-11 12:49:50",
            "updated_at": "2025-12-11 14:27:44",
            "queue_limit": 1,
            "monitoring_enabled": 1,
            "projects_count": 10
        },
        // ... more servers
    ],
    "per_page": 10,
    "total_pages": 5,
    "total_items": 5,
}

GET/api/v1/servers/:id

Retrieve a server #

This endpoint allows you to retrieve a server by providing the server id.

GET /api/v1/servers/1 Request
cURL
curl https://app.depfloy.com/api/v1/servers/183009 \
  -H "Authorization: Bearer {API_KEY}" \
  -H "Accept: application/json"
  -H "Content-Type: application/json"
Response
{
  "data": {
    "id": 1,
    "name": "production-server",
    "public_ip": "203.0.113.50",
    "private_ip": "10.0.0.1",
    "ssh_port": 22,
    // ... more properties
  }
}

GET/api/v1/servers/:id/setup-steps

Read a server’s setup record #

What the server’s build did — every step, its result and how long it took. Requires server:read.

A build records around fifty rows, so the default answer is a summary: counts per phase, where the build stands, the five slowest steps, and every step that failed or never reported its result, with the text the script captured in detail. current_step names the step a running build is sitting on — and, on a stalled one, where it stopped.

Optional attributes #

include_steps boolean

Add the full step list to the response alongside the summary.

state #

running

Steps are still outstanding.

completed

The build finished and every step reported success.

completed_with_failures

The build finished, and at least one step failed on the way. The scripts do not stop at a failing step, so this is a usable server with something worth reading in attention.

completed_with_gaps

The build finished, and at least one step never reported a result — unknown rather than failed.

stalled

Every step has settled but the build never reported reaching the end.

failed

The install script itself gave up.

not_recorded

Nothing was recorded for this server — it predates step recording.

GET /api/v1/servers/59/setup-steps Request
curl -G https://app.depfloy.com/api/v1/servers/59/setup-steps       -H "Authorization: Bearer {API_KEY}"       -H "Accept: application/json"
Response
{
  "status": "success",
  "data": {
    "server_id": 59,
    "recorded": true,
    "state": "completed_with_failures",
    "summary": {
      "total": 38,
      "pending": 0,
      "running": 0,
      "completed": 37,
      "failed": 1,
      "skipped": 0,
      "unreported": 0
    },
    "phases": [
      { "phase": "provider", "label": "Provider", "total": 3, "completed": 3, "duration_ms": 91400 },
      { "phase": "install", "label": "Installation", "total": 29, "completed": 28, "failed": 1, "duration_ms": 468300 },
      { "phase": "post_install", "label": "Finalizing", "total": 6, "completed": 6, "duration_ms": 23500 }
    ],
    "attention": [
      {
        "key": "install_curl",
        "label": "Installing curl",
        "phase": "install",
        "status": "failed",
        "status_label": "Failed",
        "detail": "E: Unable to locate package curl",
        "duration_ms": 1200,
        "started_at": "2026-08-17T09:12:41+00:00",
        "finished_at": "2026-08-17T09:12:42+00:00"
      }
    ],
    "slowest": [
      {
        "key": "install_dependencies",
        "label": "Installing dependencies",
        "phase": "install",
        "duration_ms": 214300
      }
    ],
    "total_duration_ms": 583200
  }
}
PUT/api/v1/servers/:id

Update a server #

This endpoint allows you to update a server’s information.

Attributes for updating a server #

name string

The display name for the server.

public_ip string

The public IP address of the server.

private_ip string

The private IP address of the server.

ssh_port integer

The SSH port used to connect to the server.

nat_port integer

The NAT port used to connect to the server.

timezone string

The timezone of the server.

notes string

Any additional notes about the server.

queue_limit integer

The maximum number of deploys allowed to run on this server at once. Leave it empty for no limit, which is where every server starts.

environment string

Environment tag. One of production, staging, dev, or null to clear.

PUT /api/v1/servers/183009 Request
cURL
curl -X PUT https://app.depfloy.com/api/v1/servers/183009 \
  -H "Authorization: Bearer {API_KEY}" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "production-server-updated",
    "public_ip": "203.0.113.50",
    "private_ip": "10.0.0.2",
    "ssh_port": 22
  }'
Response
{
    "message": "Server successfully updated.",
    "status": "success",
    "server_id": "183009"
}

DELETE/api/v1/servers/:id

Delete a server #

This endpoint allows you to delete a server from your account. Note: All projects will be deleted along with the server.

DELETE /api/v1/servers/183009 Request
cURL
curl -X DELETE https://app.depfloy.com/api/v1/servers/183009 \
  -H "Authorization: Bearer {API_KEY}" \
  -H "Accept: application/json"
  -H "Content-Type: application/json"
Response
{
  "status": "success",
  "message": "Server deleted successfully",
  "server_id": "183009"
}

POST/api/v1/servers/:id/reboot

Reboot a server #

This endpoint allows you to reboot a server. The request will be queued and the server will be rebooted.

POST /api/v1/servers/183009/reboot Request
cURL
curl -X POST https://app.depfloy.com/api/v1/servers/183009/reboot \
  -H "Authorization: Bearer {API_KEY}" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json"
Response
{
  "status": "success",
  "message": "Server reboot has been queued.",
  "server_id": "183009"
}

POST/api/v1/servers/:id/pin

Pin a server #

Pin a server for the current user. Pinned servers appear in their own group at the top of the Console sidebar. Pins are personal — pinning a server does not affect what other members see.

This endpoint is idempotent. Pinning an already-pinned server is a no-op.

POST /api/v1/servers/183009/pin Request
cURL
curl -X POST https://app.depfloy.com/api/v1/servers/183009/pin \
  -H "Authorization: Bearer {API_KEY}" \
  -H "Accept: application/json"
Response
{
  "status": "success",
  "is_pinned": true
}

DELETE/api/v1/servers/:id/pin

Unpin a server #

Remove the current user’s pin from a server. Idempotent — unpinning an already-unpinned server returns success without error.

DELETE /api/v1/servers/183009/pin Request
cURL
curl -X DELETE https://app.depfloy.com/api/v1/servers/183009/pin \
  -H "Authorization: Bearer {API_KEY}" \
  -H "Accept: application/json"
Response
{
  "status": "success",
  "is_pinned": false
}

POST/api/v1/servers/:id/transfer-organization

Transfer a server to another organization #

Move a server (and every project on it) to a different organization in the same Depfloy account. Requires the server:transfer permission and you must be an Owner of the destination organization.

Required attributes #

organization_id integer

The ID of the destination organization.

POST /api/v1/servers/183009/transfer-organization Request
cURL
curl -X POST https://app.depfloy.com/api/v1/servers/183009/transfer-organization \
  -H "Authorization: Bearer {API_KEY}" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{
    "organization_id": 42
  }'
Response
{
  "status": "success",
  "message": "Server transferred successfully.",
  "server_id": "183009",
  "organization_id": 42
}

Databases #

A database and the user that owns it are created together, and that user has rights to that database and nothing else on the server. Creating and removing need server:update; listing needs server:read.


GET/api/v1/servers/:id/databases

List databases #

The databases recorded on a server. Passwords are not included — read one database to get its password.

created_by_user is false for the database that came with the server. project_id is set when the database belongs to a project.

GET /api/v1/servers/183009/databases Request
cURL
curl https://app.depfloy.com/api/v1/servers/183009/databases \
  -H "Authorization: Bearer {API_KEY}" \
  -H "Accept: application/json"
Response
{
  "status": "success",
  "engine": "mysql",
  "data": [
    {
      "id": 76,
      "server_id": 183009,
      "project_id": null,
      "database_type": "mysql",
      "database_name": "depfloy",
      "username": "depfloy",
      "status": 1,
      "created_by_user": false,
      "notes": null,
      "created_at": "2026-08-01T09:12:44.000000Z"
    }
  ]
}

POST/api/v1/servers/:id/databases

Create a database #

Creates a database and its user on the server’s engine.

Body #

name string

1–63 characters: a lowercase letter first, then lowercase letters, digits or underscores. Must be unique on this server, and names the engine reserves (mysql, postgres, information_schema and the like) are refused.

username string

Defaults to name. Same character rules.

password string

At least 12 characters. Generated for you if omitted.

project_id integer

Attach the database to a project on this server. It is then removed with the project.

The reply comes back before the engine has finished. status is 0 while the database is being created, 1 once it exists and 2 if it could not be created — poll the list to follow it.

A server with no MySQL, MariaDB or PostgreSQL installation answers 422.

POST /api/v1/servers/183009/databases Request
cURL
curl -X POST https://app.depfloy.com/api/v1/servers/183009/databases \
  -H "Authorization: Bearer {API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{ "name": "analytics" }'
Response
{
  "status": "success",
  "message": "Creating the database.",
  "data": {
    "id": 91,
    "server_id": 183009,
    "project_id": null,
    "database_type": "mysql",
    "database_name": "analytics",
    "username": "analytics",
    "status": 0
  }
}

GET/api/v1/servers/:id/databases/:database

Retrieve a database #

One database, with its password. Separate from the list on purpose — reading a password is a request you make deliberately. Needs server:update.

GET /api/v1/servers/183009/databases/91 Request
cURL
curl https://app.depfloy.com/api/v1/servers/183009/databases/91 \
  -H "Authorization: Bearer {API_KEY}" \
  -H "Accept: application/json"
Response
{
  "status": "success",
  "data": {
    "id": 91,
    "server_id": 183009,
    "project_id": null,
    "database_type": "mysql",
    "database_name": "analytics",
    "username": "analytics",
    "status": 1,
    "created_by_user": true,
    "password": "generated-password"
  }
}

DELETE/api/v1/servers/:id/databases/:database

Delete a database #

Drops the database and its user. What is in it goes with it.

Two are refused with 422: the database that came with the server, because it holds the credentials Depfloy uses to manage the engine, and one that belongs to a project — delete the project instead and its database goes with it.

DELETE /api/v1/servers/183009/databases/91 Request
cURL
curl -X DELETE https://app.depfloy.com/api/v1/servers/183009/databases/91 \
  -H "Authorization: Bearer {API_KEY}" \
  -H "Accept: application/json"
Response
{
  "status": "success",
  "message": "Removing the database."
}

GET/api/v1/server-providers

List server providers #

List the server providers configured on your account. Requires the server:create permission.

Use it to find the provider ID the options endpoint below takes, and the id a create call needs as provider_id. provider_type is the string you pass back when creating a server — hetzner, aws or digitalocean. label is for display.

GET /api/v1/server-providers Request
cURL
curl https://app.depfloy.com/api/v1/server-providers \
  -H "Authorization: Bearer {API_KEY}" \
  -H "Accept: application/json"
Response
{
  "status": "success",
  "data": [
    {
      "id": 7,
      "name": "Hetzner (main)",
      "provider_type": "hetzner",
      "label": "Hetzner"
    },
    {
      "id": 3,
      "name": "DigitalOcean (prod)",
      "provider_type": "digitalocean",
      "label": "Digital Ocean"
    }
  ]
}

GET/api/v1/server-providers/:id/options

Retrieve a provider’s options #

What a provider can be asked for: the locations it runs in, and — once you name one — the server types sold there with their monthly price. Requires the server:create permission.

Server types are priced per location, so the two questions cannot be answered in one call. Omit location for the location list; pass it to get server types and installable images for that location. A server type with no price in the location is not offered there and is left out rather than returned as an option that would fail at creation.

Every price carries its own currency: EUR on Hetzner, USD on AWS and DigitalOcean. monthly_price_net excludes VAT and monthly_price_gross includes it — AWS and DigitalOcean list prices carry none, so both fields hold the same number there.

Optional attributes #

location string

A location name from the first call — nbg1 on Hetzner, eu-central-1 on AWS, fra1 on DigitalOcean. Omit it to list locations.

Two answers differ by provider. On AWS the response also carries networks, the VPCs in that region with their subnets, because an AWS order cannot be placed without a subnet id; if those cannot be read the call fails rather than returning an empty list. DigitalOcean has no networks key at all — a VPC is optional there, so an empty list would read as a choice that has to be made and cannot be. And disk_gb is null on AWS, where the root volume is ordered and billed separately; Hetzner and DigitalOcean both include one.

Hetzner, AWS and DigitalOcean providers can be listed. A provider type Depfloy holds credentials for but cannot read a catalogue from returns 422, naming the provider. An ID you cannot reach returns 404.

GET /api/v1/server-providers/7/options Request
cURL
curl "https://app.depfloy.com/api/v1/server-providers/7/options?location=nbg1" \
  -H "Authorization: Bearer {API_KEY}" \
  -H "Accept: application/json"
Response
{
  "status": "success",
  "data": {
    "location": "nbg1",
    "server_types": [
      {
        "name": "cx22",
        "description": "CX22",
        "cores": 2,
        "memory_gb": 4,
        "disk_gb": 40,
        "architecture": "x86",
        "monthly_price_net": "3.7900",
        "monthly_price_gross": "4.5101",
        "currency": "EUR"
      }
    ],
    "images": []
  }
}