dFlow API
Process is up. This check does not touch a database.
application/json- response
status*stringcurl -X GET 'https://k8s.dflow.sh/healthz'{ "status": "ok"}Registered checks passed.
application/json- response
status*stringcurl -X GET 'https://k8s.dflow.sh/readyz'{ "status": "ready"}Build version and API version.
application/json- response
version*stringapi_version*stringcurl -X GET 'https://k8s.dflow.sh/v1/version'{ "version": "dev", "api_version": "v1"}Token id, display prefix, role, scope, and workspace id. A user session also includes user_id, email, and credential_kind user. An API token includes credential_kind api_token and omits user_id and email. The bearer secret is absent.
application/json- response
curl -X GET 'https://k8s.dflow.sh/v1/whoami'{}User created. A token pair is included when email verification is off, and workspace_id is that user's personal workspace. When verification is on, delivery is log or smtp, the verify token is not in this response, and the personal workspace is created at the first successful login.
curl -X POST 'https://k8s.dflow.sh/v1/auth/register'curl -X POST 'https://k8s.dflow.sh/v1/auth/verify'curl -X POST 'https://k8s.dflow.sh/v1/auth/login'curl -X POST 'https://k8s.dflow.sh/v1/auth/refresh'curl -X POST 'https://k8s.dflow.sh/v1/auth/logout'Accepted. delivery is log or smtp. The response does not say whether the email exists and does not include the reset token.
curl -X POST 'https://k8s.dflow.sh/v1/auth/forgot'curl -X POST 'https://k8s.dflow.sh/v1/auth/reset'curl -X POST 'https://k8s.dflow.sh/v1/auth/workspace'curl -X POST 'https://k8s.dflow.sh/v1/auth/invites/accept'The invite token is shown once. delivery is log or smtp when a copy was also sent. A personal workspace returns precondition.
curl -X POST 'https://k8s.dflow.sh/v1/workspaces/{workspace_id}/invites'A verified user receives every workspace they belong to, including the personal one, even when the session is inside one workspace. An API token receives only its workspace. A platform owner receives a page of every workspace. Any verified user can create another workspace. An API token cannot. An invite into the personal workspace is rejected.
Items of id and name. next is null when the page is complete.
curl -X GET 'https://k8s.dflow.sh/v1/workspaces'Workspace created. personal is false. Any verified user becomes the owner. An API token cannot create a workspace. The platform owner is forbidden. The personal workspace from signup stays private and cannot accept invites.
curl -X POST 'https://k8s.dflow.sh/v1/workspaces'curl -X GET 'https://k8s.dflow.sh/v1/workspaces/{workspace_id}'stored is true or false. The token is absent.
curl -X GET 'https://k8s.dflow.sh/v1/workspaces/{workspace_id}/github-token'The token is encrypted and is not returned. A later GET reports stored true or false. A workspace owner or admin stores it. The platform owner is forbidden. An empty DFLOW_DATA_KEY returns HTTP 412. The token is not placed in a clone URL.
stored is true. The token is absent.
curl -X PUT 'https://k8s.dflow.sh/v1/workspaces/{workspace_id}/github-token'Project items. next is null when the page is complete.
curl -X GET 'https://k8s.dflow.sh/v1/workspaces/{workspace_id}/projects'The workspace id is in the path. A repeated Idempotency-Key with the same name returns HTTP 200. A different name with that key returns 409. A missing key still creates the project.
The project row. No namespace is created.
curl -X POST 'https://k8s.dflow.sh/v1/workspaces/{workspace_id}/projects'Deleted environments are omitted. This route does not read Kubernetes.
Environment items.
curl -X GET 'https://k8s.dflow.sh/v1/projects/{project_id}/environments'Stores a namespace name and does not create that namespace in Kubernetes. namespace_created is false. Optional region, such as in or us, selects one cluster in that region. The application and its database stay on that cluster. An omitted region uses the single workspace cluster, or the hosted cluster when the workspace has none. When no cluster is registered, the environment is stored and a later deploy asks for one. The stored cluster_id is not changed later.
The environment row.
curl -X POST 'https://k8s.dflow.sh/v1/projects/{project_id}/environments'Returns HTTP 202 and a pending environment.delete operation when no application row exists. Returns HTTP 412 when an application still exists. A second delete while the environment is deleting returns the same operation. This route does not delete a Kubernetes namespace.
The delete operation was accepted.
curl -X DELETE 'https://k8s.dflow.sh/v1/environments/{env_id}'Deleted applications are omitted. desired is the latest deployment. observed is the last worker snapshot, or null.
Application items. next is null when the page is complete.
curl -X GET 'https://k8s.dflow.sh/v1/environments/{env_id}/applications'The environment must be active. A viewer cannot create one. The platform owner cannot create one. No Kubernetes object is created.
The application. desired and observed are null.
curl -X POST 'https://k8s.dflow.sh/v1/environments/{env_id}/applications'Requires a bearer token. Returns product capability, not tenant data. The registered provider is postgresql, with capabilities provision, status, and deprovision.
Provider name and capability list for each registered provider.
application/json- response
items*array<>curl -X GET 'https://k8s.dflow.sh/v1/providers'{ "items": [ { "name": "postgresql", "capabilities": [ "provision", "status", "deprovision" ] } ]}Deleted instances are omitted. Requires workspace membership.
Service instance items.
curl -X GET 'https://k8s.dflow.sh/v1/environments/{env_id}/services'Validates parameters, inserts a pending service_instances row, and returns a pending service.provision operation. Provider postgresql accepts parameters database, storage, and optional version. version is 16, 17, or 18. Any other value returns 400 and creates no instance. Omitting version leaves the cluster image unset. application_id, when set, records the new service on that application's dflow.json before the database is ready. A missing provider capability returns 412 and creates no operation. An unknown provider name returns 404.
application/json- body
provider*stringname*stringcapability*stringparameters?application_id?stringApplication whose stored dflow.json should name this service.
Accepted. The worker will call the provider.
curl -X POST 'https://k8s.dflow.sh/v1/environments/{env_id}/services' \ -H 'Content-Type: application/json' \ -d '{ "provider": "fake", "name": "demo", "capability": "provision", "parameters": {}}'Returns desired and observed JSON without secret values.
The service instance.
curl -X GET 'https://k8s.dflow.sh/v1/services/{svc_id}'Requires header Confirm-Name equal to the service name. Returns HTTP 202 and a pending service.deprovision operation. Data is deleted without a backup.
Confirm-Name*stringAccepted.
curl -X DELETE 'https://k8s.dflow.sh/v1/services/{svc_id}' \ -H 'Confirm-Name: string'After the service is ready, the first call returns host, port, database, username, and password and writes an audit event. A second call returns 412 credentials_already_read and does not return the password. The runtime Kubernetes Secret is unchanged.
One-time credential payload.
application/json- response
host*stringport*stringdatabase*stringusername*stringpassword*stringcurl -X POST 'https://k8s.dflow.sh/v1/services/{svc_id}/credentials'{ "host": "string", "port": "string", "database": "string", "username": "string", "password": "string"}Writes DFLOW_DATABASE_HOST, PORT, NAME, and USERNAME as env and DFLOW_DATABASE_PASSWORD as a secret, then queues application.deploy. Fails with 409 if any of those keys already exist.
application/json- body
service_id*stringAccepted deploy operation.
curl -X POST 'https://k8s.dflow.sh/v1/applications/{app_id}/service-bindings' \ -H 'Content-Type: application/json' \ -d '{ "service_id": "string"}'Returns the desired image, port, and replica count together with the last observed status. This route reads PostgreSQL only.
The application.
curl -X GET 'https://k8s.dflow.sh/v1/applications/{app_id}'Requires header Confirm-Name equal to the application name. Returns HTTP 202 and a pending application.delete operation. With no stored cluster credential the worker marks the application deleted without calling Kubernetes. The desired image row is kept. When the application is already deleting, send Force: true (or force=1) to re-queue delete.
Confirm-Name*stringForce?"true"Re-queue delete when status is already deleting.
"true"The delete operation was accepted.
curl -X DELETE 'https://k8s.dflow.sh/v1/applications/{app_id}' \ -H 'Confirm-Name: string'image is required. port defaults to 8080. replicas defaults to 1 and cannot exceed 5. The image must match letters, digits, and . _ / : @ + -, up to 512 characters. HTTP 202 means the operation was recorded. It does not mean the workload is ready. Until a cluster credential is stored, the worker fails the operation with cluster credential is not stored and creates no object. A repeated Idempotency-Key with the same image, port, and replicas returns that operation. A different body returns 409. A missing key still creates the deployment. GET observed, once a worker has written it, contains conditions Progressing, Available, and Degraded.
A pending application.deploy operation.
curl -X POST 'https://k8s.dflow.sh/v1/applications/{app_id}/deployments'repo is an https github.com URL with no token in the URL. Omit repo to clone build.repo from the application's stored dflow.json. An explicit repo is the clone URL. A dflow.json in that repository still supplies the other settings. A template install clones build.repo, branch, and root from the submitted document and does not replace that document with a file from the repository. A public repository needs no token. A private repository uses the stored workspace token and returns HTTP 412 when that token is missing. The clone URL stays free of the token. The server clones it, builds it with Railpack, pushes the image to DFLOW_REGISTRY, and deploys that image. HTTP 202 is the build operation. An empty registry is HTTP 412. A failed build returns the build log on the operation. The message says whether the failure is in the repository or in the builder. dFlow does not open a GitHub pull request.
A pending application.build operation.
curl -X POST 'https://k8s.dflow.sh/v1/applications/{app_id}/builds'Each item has id, revision, image_digest, status, and current. current is true when that succeeded release is the desired image. An application in another workspace returns HTTP 404.
The release list. items is empty when the application has no release.
curl -X GET 'https://k8s.dflow.sh/v1/applications/{app_id}/releases'Body is {"release_id":"rel_..."}. The response is HTTP 202 and an application.deploy operation. The image is that release's digest. Rollback does not start a build. An unknown release, or a release for another application, returns HTTP 404. A release that is not succeeded returns HTTP 412. The release that is already the desired image returns HTTP 409 and error code conflict, message already current.
A pending application.deploy operation.
curl -X POST 'https://k8s.dflow.sh/v1/applications/{app_id}/rollbacks'curl -X GET 'https://k8s.dflow.sh/v1/applications/{app_id}/volumes'Requires Idempotency-Key. size_gi is 1 through 10. storage_class must be on the cluster capability report. mount_path is an absolute directory. One volume per application. HTTP 202 is not Bound. The operation succeeds when the claim phase is Bound. Delete removes the disk.
curl -X POST 'https://k8s.dflow.sh/v1/applications/{app_id}/volumes'Body confirm_name must equal the stored name. Requires Idempotency-Key. Data is deleted.
curl -X POST 'https://k8s.dflow.sh/v1/volumes/{volume_id}/delete'curl -X GET 'https://k8s.dflow.sh/v1/applications/{app_id}/jobs'Requires Idempotency-Key. image is required. schedule of five cron fields creates a CronJob. Omitting schedule creates a Job. privileged, host_path, host_network, host_pid, host_ipc, and security_context are rejected. The platform sets the security context.
curl -X POST 'https://k8s.dflow.sh/v1/applications/{app_id}/jobs'Body confirm_name must equal the stored name. Requires Idempotency-Key.
curl -X POST 'https://k8s.dflow.sh/v1/jobs/{job_id}/delete'Returns the recipes in templates/*/dflow.json. supabase is not listed. examples/ is not listed.
curl -X GET 'https://k8s.dflow.sh/v1/templates'Body {"name":"umami"} installs an official recipe. A dflow.json document, with applications and services, installs that document. Requires Idempotency-Key. HTTP 202 starts the install. The same template can be installed again in one environment. The application and database service keep the recipe names when those names are free. When either name is taken, both gain the same four-character suffix a route adds to a taken hostname. The operation succeeds only when the public URL returns HTTP 200. One-time secrets are read from GET /v1/template-installs/{install_id} once.
curl -X POST 'https://k8s.dflow.sh/v1/environments/{env_id}/template-installs'curl -X GET 'https://k8s.dflow.sh/v1/template-installs/{install_id}'curl -X GET 'https://k8s.dflow.sh/v1/applications/{app_id}/files'Body path and contents. path is absolute and is not /. Contents are not returned later. Requires a deployment.
curl -X PUT 'https://k8s.dflow.sh/v1/applications/{app_id}/files'curl -X GET 'https://k8s.dflow.sh/v1/workspaces/{workspace_id}/tokens'curl -X POST 'https://k8s.dflow.sh/v1/workspaces/{workspace_id}/tokens'The response is HTTP 200 because the check finishes inside the request. When DFLOW_KUBECONFIG_KEY is set, a successful check stores an AES-256-GCM blob and the operation status is succeeded. When that variable is empty, status failed with error_code precondition means the report was saved and the credential was not stored. The response has no kubeconfig and no ciphertext. The body requires region, a short name such as in or us. This cluster stays on that workspace. A body with shared true is rejected. A platform cluster is POST /v1/admin/clusters and has no workspace. A missing Idempotency-Key creates no row.
Idempotency-Key*stringThe operation already finished. This is not a stored credential.
curl -X POST 'https://k8s.dflow.sh/v1/workspaces/{workspace_id}/clusters' \ -H 'Idempotency-Key: string'The cluster row. credential_state is not_persisted or stored. The response has no kubeconfig and no ciphertext.
curl -X GET 'https://k8s.dflow.sh/v1/workspaces/{workspace_id}/clusters/{cluster_id}'Platform owner only. Each item has id, name, provider, and credential_state. workspace_id is present for a private cluster. A platform cluster has no workspace. The response has no kubeconfig.
Items ordered by id. An empty list is an empty items array.
curl -X GET 'https://k8s.dflow.sh/v1/admin/clusters'Platform owner only. The cluster has a region and no workspace. Every workspace can place an environment on it. The response is HTTP 200 because the check finishes inside the request. The response has no kubeconfig. A missing Idempotency-Key creates no row.
Idempotency-Key*stringThe operation already finished.
curl -X POST 'https://k8s.dflow.sh/v1/admin/clusters' \ -H 'Idempotency-Key: string'Platform owner only. Each item has id, type, status, and workspace_id. message is present when the operation failed. page_size defaults to 50 and cannot exceed 200. There is no next page.
The newest operations, newest first.
curl -X GET 'https://k8s.dflow.sh/v1/admin/operations'Platform owner only. recovery_point and recovery_time are the word assumption. They are not a commitment. objective_met is false when no successful run finished inside 24 hours. The response has no database URL and no platform key.
The newest backup runs.
curl -X GET 'https://k8s.dflow.sh/v1/admin/backups'Requires Idempotency-Key. HTTP 202 means the dump was queued. It does not mean the dump finished. An empty DFLOW_BACKUP_DIR or a directory on the database volume returns 412 and writes no file.
operation_id and status pending.
curl -X POST 'https://k8s.dflow.sh/v1/admin/backups'HTTP 200 includes a failed operation. The body has no idempotency key and no credential.
The operation. status failed is still HTTP 200.
curl -X GET 'https://k8s.dflow.sh/v1/operations/{operation_id}'A pending operation becomes cancelled. A running operation stays running until the handler stops. A finished operation is unchanged.
The operation was pending or running.
curl -X POST 'https://k8s.dflow.sh/v1/operations/{operation_id}/cancel'curl -X POST 'https://k8s.dflow.sh/v1/tokens/{token_id}/revoke'Returns the tailed log of each container for pods labeled with this application. Query tail defaults to 100 and must be from 1 to 1000. Query container selects one container name. No pods, or pods with no log text, returns an empty lines array and message No logs yet. A bearer token, a platform token, a URL password, or a kubeconfig secret in the text is replaced with [redacted]. The route does not hold a follow stream. No selected cluster returns 412.
Log lines for this application's pods.
application/json- response
lines*array<>message?stringcurl -X GET 'https://k8s.dflow.sh/v1/applications/{app_id}/logs'{ "lines": [], "message": "No logs yet."}Returns events whose involved object is a pod labeled for this application. This is separate from the platform operation list. page_size defaults to 50 and must be from 1 to 200. An empty page includes message No pod events yet. No selected cluster returns 412.
Kubernetes events for this application's pods.
application/json- response
events*array<>next_page_token?stringmessage?stringcurl -X GET 'https://k8s.dflow.sh/v1/applications/{app_id}/pod-events'{ "events": [], "message": "No pod events yet."}Items are operation records. They are not Kubernetes Event objects. An empty list includes the message No events yet.
Operation history for the application.
application/json- response
items*array<>message?stringcurl -X GET 'https://k8s.dflow.sh/v1/applications/{app_id}/events'{ "items": [], "message": "No events yet."}tls is tls_disabled, pending, or ready. custom_domains lists the extra hostnames. No platform row returns 404.
The stored platform host, its custom hostnames, and the last observation.
curl -X GET 'https://k8s.dflow.sh/v1/applications/{app_id}/route'Returns 202 and an operation of type application.route. An omitted host uses the application, project, and environment names plus DFLOW_APPS_DOMAIN. That platform hostname is the only name under the platform suffix. A host outside that suffix is a custom hostname. Adding one creates the platform hostname first when it is missing. An application stores at most 10 custom hostnames. A name under the platform suffix, other than the stored platform hostname, returns 400. An empty ingress class or an empty apps domain returns 412. The response has no kubeconfig.
The route operation was accepted.
curl -X PUT 'https://k8s.dflow.sh/v1/applications/{app_id}/route'Returns 202 and an operation of type application.route. The platform hostname stays. An unknown host returns 404.
The route operation was accepted.
curl -X DELETE 'https://k8s.dflow.sh/v1/applications/{app_id}/route/{host}'Returns revision and values. Secret values are never included.
The stored non-secret map.
curl -X GET 'https://k8s.dflow.sh/v1/applications/{app_id}/env'Replaces the whole non-secret map. A changed map returns 202 and an application.deploy operation when an image exists. An unchanged map returns 200. With no image yet the map is stored and the response is 200 with status stored. The next image deploy includes it.
The map was unchanged, or it was stored before any image deploy.
curl -X PUT 'https://k8s.dflow.sh/v1/applications/{app_id}/env'Returns sorted key names only. Values and ciphertext are never returned.
The key name list.
curl -X GET 'https://k8s.dflow.sh/v1/applications/{app_id}/secrets'Returns 202 and an application.deploy operation when an image exists.
A deploy operation was accepted.
curl -X DELETE 'https://k8s.dflow.sh/v1/applications/{app_id}/secrets/{key}'Stores AES-256-GCM ciphertext under DFLOW_DATA_KEY. Returns 202 and an application.deploy operation when an image exists. With no image yet the secret is stored and the response is 200 with status stored. The next image deploy includes it. GET of secrets never returns the value. A body field named data_key is rejected.
The secret was stored before any image deploy.
curl -X PUT 'https://k8s.dflow.sh/v1/applications/{app_id}/secrets/{key}'How is this guide?