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.
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, ornullfor 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.
/api/v1/serversCreate 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,digitaloceanorcustom. Treated ascustomwhen omitted. - provider_id integer
-
Required for
hetzner,awsanddigitalocean. 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_typeiscustom, 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
networksthe 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,gp2orio2. Defaults togp3. - 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.
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
}'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
}'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"
}'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"
}'{
"status": "provisioning",
"message": "Server creation started. You will receive real-time updates.",
"server_id": 42
}{
"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."
}
}/api/v1/serversList all servers #
This endpoint allows you to retrieve a paginated list of all your servers.
curl -G https://app.depfloy.com/api/v1/servers \
-H "Authorization: Bearer {API_KEY}" \
-H "Accept: application/json" \
-H "Content-Type: application/json"{
"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,
}/api/v1/servers/:idRetrieve a server #
This endpoint allows you to retrieve a server by providing the server id.
curl https://app.depfloy.com/api/v1/servers/183009 \
-H "Authorization: Bearer {API_KEY}" \
-H "Accept: application/json"
-H "Content-Type: application/json"{
"data": {
"id": 1,
"name": "production-server",
"public_ip": "203.0.113.50",
"private_ip": "10.0.0.1",
"ssh_port": 22,
// ... more properties
}
}/api/v1/servers/:id/setup-stepsRead 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.
curl -G https://app.depfloy.com/api/v1/servers/59/setup-steps -H "Authorization: Bearer {API_KEY}" -H "Accept: application/json"{
"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
}
}/api/v1/servers/:idUpdate 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, ornullto clear.
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
}'{
"message": "Server successfully updated.",
"status": "success",
"server_id": "183009"
}/api/v1/servers/:idDelete a server #
This endpoint allows you to delete a server from your account. Note: All projects will be deleted along with the server.
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"{
"status": "success",
"message": "Server deleted successfully",
"server_id": "183009"
}/api/v1/servers/:id/rebootReboot a server #
This endpoint allows you to reboot a server. The request will be queued and the server will be rebooted.
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"{
"status": "success",
"message": "Server reboot has been queued.",
"server_id": "183009"
}/api/v1/servers/:id/pinPin 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.
curl -X POST https://app.depfloy.com/api/v1/servers/183009/pin \
-H "Authorization: Bearer {API_KEY}" \
-H "Accept: application/json"{
"status": "success",
"is_pinned": true
}/api/v1/servers/:id/pinUnpin a server #
Remove the current user’s pin from a server. Idempotent — unpinning an already-unpinned server returns success without error.
curl -X DELETE https://app.depfloy.com/api/v1/servers/183009/pin \
-H "Authorization: Bearer {API_KEY}" \
-H "Accept: application/json"{
"status": "success",
"is_pinned": false
}/api/v1/servers/:id/transfer-organizationTransfer 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.
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
}'{
"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.
/api/v1/servers/:id/databasesList 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.
curl https://app.depfloy.com/api/v1/servers/183009/databases \
-H "Authorization: Bearer {API_KEY}" \
-H "Accept: application/json"{
"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"
}
]
}/api/v1/servers/:id/databasesCreate 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_schemaand 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.
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" }'{
"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
}
}/api/v1/servers/:id/databases/:databaseRetrieve 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.
curl https://app.depfloy.com/api/v1/servers/183009/databases/91 \
-H "Authorization: Bearer {API_KEY}" \
-H "Accept: application/json"{
"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"
}
}/api/v1/servers/:id/databases/:databaseDelete 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.
curl -X DELETE https://app.depfloy.com/api/v1/servers/183009/databases/91 \
-H "Authorization: Bearer {API_KEY}" \
-H "Accept: application/json"{
"status": "success",
"message": "Removing the database."
}/api/v1/server-providersList 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.
curl https://app.depfloy.com/api/v1/server-providers \
-H "Authorization: Bearer {API_KEY}" \
-H "Accept: application/json"{
"status": "success",
"data": [
{
"id": 7,
"name": "Hetzner (main)",
"provider_type": "hetzner",
"label": "Hetzner"
},
{
"id": 3,
"name": "DigitalOcean (prod)",
"provider_type": "digitalocean",
"label": "Digital Ocean"
}
]
}/api/v1/server-providers/:id/optionsRetrieve 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 —
nbg1on Hetzner,eu-central-1on AWS,fra1on 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.
curl "https://app.depfloy.com/api/v1/server-providers/7/options?location=nbg1" \
-H "Authorization: Bearer {API_KEY}" \
-H "Accept: application/json"{
"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": []
}
}