Migrate to RunxBuild and earn up to $50 in hosting credit on your first deposit.

Calculate your savings
unxBuild

Dokploy API: Automating a Self-Hosted PaaS From Outside the Dashboard

Sean

Platform Writer

Aug 27, 2026
7 min read

Dokploy’s API is a straightforward REST surface authenticated by a header-based API key. If you can generate a key and send one header, you can script anything the dashboard does.

Dokploy API: Automating a Self-Hosted PaaS From Outside the Dashboard

Dokploy is an open-source platform-as-a-service you run on your own infrastructure, and the API is what turns it from a dashboard into something you can automate. The mechanics are simple; the interesting part is what the responses contain and what that implies about how you handle them.

Table of contents

Authentication

Generate an API key in the dashboard settings and send it as a header on every request.

export DOKPLOY_URL=https://dokploy.example.com
export DOKPLOY_KEY=your-generated-api-key

curl -X GET \
  "$DOKPLOY_URL/api/project.all" \
  -H 'accept: application/json' \
  -H "x-api-key: $DOKPLOY_KEY"

Note the header name - it is a custom header, not a standard bearer token. Sending it in an Authorization header will fail with an authentication error that does not explain why, and it is the first thing to check when a script that looks correct returns 401.

The endpoint naming is notable too: it is dot-separated resource and action rather than the path-and-verb style most REST APIs use. Once you see the pattern, guessing an endpoint name is usually reliable, and the instance serves its own API documentation which is the authoritative list for your version.

Version matters here more than with a hosted product. Dokploy is self-hosted and evolving, so the API surface on your instance is whatever version you installed. Check your own documentation endpoint rather than trusting an example from a blog post, including this one.

What a project response contains

The project listing returns projects with their nested resources - applications, databases of each supported type, and compose stacks.

[
  {
    "projectId": "klZKsyw5g-QT_jrWJ5T-w",
    "name": "Random",
    "createdAt": "2024-06-19T15:05:58.785Z",
    "applications": [],
    "mysql": [
      {
        "mysqlId": "N3cudwO46TiDXzBm4SaQ1",
        "name": "mysql",
        "databaseName": "mysql",
        "databaseUser": "mysql",
        "databasePassword": "...",
        "dockerImage": "mysql:8",
        "memoryLimit": null,
        "cpuLimit": null,
        "externalPort": null,
        "applicationStatus": "done"
      }
    ],
    "postgres": [],
    "redis": [],
    "compose": []
  }
]

Read that payload carefully, because it contains database passwords and root passwords in plain text. That is a design consequence of the API being the same interface the dashboard uses, and it has direct implications for how you script against it.

  • Never log a raw project response. A debug print during development puts every database credential into your CI logs, where they persist and are visible to anyone with access to the run.
  • Extract what you need and discard the rest. Do not pass whole response objects around your automation.
  • Treat the API key as equivalent to full credential access, because it is. Anyone holding it can enumerate every database password on the instance.
  • Do not expose the API to the internet without restriction. Put it behind a VPN, an allowlist, or a reverse proxy that restricts source addresses.

That last point is the one worth acting on today if you have not. A self-hosted PaaS control plane reachable from anywhere, protected by a single static key, is a large amount of access behind a single string.

Scripting common operations

The pattern for most automation is: list to find an identifier, then act on that identifier.

# Find a project by name and get its id
PROJECT_ID=$(curl -s -H "x-api-key: $DOKPLOY_KEY" \
  -H 'accept: application/json' \
  "$DOKPLOY_URL/api/project.all" \
  | jq -r '.[] | select(.name=="production") | .projectId')

# List applications and their status
curl -s -H "x-api-key: $DOKPLOY_KEY" \
  -H 'accept: application/json' \
  "$DOKPLOY_URL/api/project.all" \
  | jq -r '.[].applications[] | "\(.name)\t\(.applicationStatus)"'

Because identifiers are opaque generated strings rather than readable names, resolving by name first is the normal shape. Hardcoding an identifier works until the resource is recreated, at which point the script fails against a resource that no longer exists.

For deployment triggers, the API can be called from CI after a successful build, which is the most common reason to reach for it at all.

# In a CI job, after tests pass
curl -s -X POST \
  -H "x-api-key: $DOKPLOY_KEY" \
  -H 'Content-Type: application/json' \
  -d "{\"applicationId\": \"$APP_ID\"}" \
  "$DOKPLOY_URL/api/application.deploy"

Check the exact endpoint and payload shape against your instance’s documentation - this is precisely the area where versions differ. Always check the HTTP status rather than assuming success, since a 200 with an error body is a shape some endpoints use.

Where self-hosting a PaaS costs you

Running your own platform is a legitimate choice and the appeal is obvious: full control, no vendor lock-in, and a bill that is just the servers. It is worth being honest about the ongoing work it involves, because that is the part that is invisible at install time.

  • You patch it. The platform itself, its dependencies, and the host operating system. A control plane with a known vulnerability is a serious problem, because it holds credentials for everything it manages.
  • You back it up. Both the applications and the platform’s own state. Restoring a PaaS whose configuration database is gone is a rebuild.
  • You are the on-call. When the control plane is down at 2am, there is nobody to escalate to.
  • You handle upgrades. Including the ones that change the API you automated against.
  • Single host is single point of failure. Most self-hosted PaaS installs run on one machine. When that machine has a problem, everything on it does.

None of these are reasons not to self-host. They are the actual cost, and it is a time cost rather than a line on an invoice, which is why it tends to be underestimated when the comparison is made.

The honest framing: self-hosting is cheaper in money and more expensive in attention. If you have the attention available and value the control, it is a good trade. If the attention is the scarce resource - which for a small team shipping a product it usually is - then the arithmetic works out differently.

The managed comparison

The alternative shape is the same capabilities without the control plane being your responsibility. A repository push produces a build log and a live route, environment variables live in the platform, runtime logs sit beside the deploy that produced them, and rollback to the previous deploy is a button rather than a procedure.

On RunxBuild that covers Node, Next.js, Python, Go, Ruby, Java, .NET, and Docker services, with managed Postgres and MySQL beside them - backups, connection limits, user management, and private networking included rather than configured. Autoscaling moves between a floor and a ceiling plan you pick, and plans start at Free, then Dev at $4 and Basic at $6, up the ladder as the workload grows.

What you give up is exactly what self-hosting gives you: the ability to change anything about the platform itself. If your requirements include running arbitrary databases the managed offering does not cover, or modifying platform behaviour, self-hosting remains the right answer and the API above is how you automate it.

What you get back is the attention. Nobody patches the control plane, nobody is paged when it fails, and an upgrade does not break the automation you wrote last quarter.

How this fits the rest of the stack

Self-hosting a platform is cheaper in money and more expensive in attention, and it is worth pricing both sides before deciding. The RunxBuild hosting calculator shows the managed shape as separate line items - the service, the managed Postgres or MySQL, storage, and bandwidth - so the comparison against a server bill plus your own time is made against real numbers.

Useful related references:

FAQ

How do I authenticate with the Dokploy API?

Generate an API key in the dashboard settings and send it in a custom header on every request - not as a bearer token in the Authorization header. Sending it the standard way fails with an authentication error that does not explain the cause.

Does the Dokploy API return database passwords?

Yes. Project listings include database passwords and root passwords in plain text, because the API is the same interface the dashboard uses. Never log a raw project response, and treat the API key as equivalent to full credential access for the instance.

Can I trigger a Dokploy deployment from CI?

Yes - that is the most common reason to use the API. Post to the deployment endpoint with the application identifier after your tests pass. Check the exact endpoint and payload against your own instance’s API documentation, since the surface changes between versions.

Is it safe to expose the Dokploy API to the internet?

Not without restriction. A single static key grants full control-plane access, including the ability to read every database password on the instance. Put it behind a VPN, a source-address allowlist, or a reverse proxy that restricts access.

What is the real cost of self-hosting a PaaS?

Attention rather than money. You patch the platform and its host, back up both applications and the platform’s own state, handle upgrades that may break your automation, and are the escalation path when the control plane fails. Most installs also run on a single host, which is a single point of failure.

#dokploy api#self-hosted paas#deployment automation#api key#devops