Deploy and manage hosted sites programmatically — create sites, attach custom domains, issue certificates, and manage storage over plain HTTP. Available on the Whitelabel Agency plan.
Every request is authenticated with your account API key, sent as a header:
X-API-Key: dvh_your_key_here
Generate or rotate the key in your dashboard under Account → API access. The raw key is shown only once at creation — store it securely. API access requires a Whitelabel Agency plan.
401403Base URL for every path below:
https://app.devani.io/api/v1
Content-Type: application/json on POST/PATCH.{ "detail": "message" } with a non-2xx status (validation 400/422, auth 401, forbidden 403, not found 404).400 with a message.POST /sites blocks until the site is provisioned and serving (~40s), so the response is the live site.Your plan, effective limits, current usage, and the hub MCP connection URL.
curl https://app.devani.io/api/v1/account -H "X-API-Key: $KEY"
{
"email": "you@agency.com",
"plan": { "key": "whitelabel", "name": "Whitelabel Agency" },
"limits": { "sites": 35, "staging": 10, "cdn_mb": 307200, "custom_domains": 35 },
"usage": { "sites": 4, "staging": 0, "cdn_allocated_mb": 20480 },
"hub_mcp_url": "https://app.devani.io/api/mcp"
}
List every site on your account.
Deploy a new site. Returns when it's live on its free *.devani.studio address.
| Field | Type | Notes |
|---|---|---|
slug | string | Required. The subdomain label (slug.devani.studio), 3–40 chars. |
display_name | string | Optional. Friendly name. |
custom_domain | string | Optional. Attach a custom domain at creation (DNS auto-configured if you've connected Cloudflare; otherwise records are returned to add). |
staging | bool | Optional. Provision a staging site (counts against the staging limit, free subdomain only). |
curl -X POST https://app.devani.io/api/v1/sites \
-H "X-API-Key: $KEY" -H "Content-Type: application/json" \
-d '{"slug":"acme","display_name":"Acme Co"}'
The response is a Site object — including devani_admin with the site's CMS login and its per-site MCP URL.
slug, you get the existing site back (201) instead of an error — so a dropped connection never leaves you guessing. Note: the one-time CMS password is only shown on the first successful create; a retry won't repeat it (regenerate from the dashboard if lost). A custom domain already held by one of your own sites returns a clear message naming that site.Full detail for one site, including devani_admin (CMS login + MCP URL) and any pending custom-domain setup.
Permanently tear a site down (files, database, vhost, certificate, and any custom-hostname registration).
Attach a custom domain. If you've connected your Cloudflare token (Whitelabel auto-DNS), the records are created for you; otherwise the records to add are returned in the site's custom_domain_setup. The domain goes live on HTTPS automatically once it validates.
| Field | Type | Notes |
|---|---|---|
domain | string | Required. e.g. www.client.com. |
replace_dns | bool | Optional. If a conflicting DNS record already exists, replace it (a live-domain cutover). Default false surfaces the conflict instead. |
curl -X POST https://app.devani.io/api/v1/sites/12/domains \
-H "X-API-Key: $KEY" -H "Content-Type: application/json" \
-d '{"domain":"www.client.com"}'
(Re)run the automatic DNS for an attached domain — use replace=true to confirm replacing a conflicting record.
Detach a custom domain.
*.devani.studio address as the instant URL. Once a custom domain's certificate is active it becomes the primary, and the free subdomain automatically 301-redirects to it.Issue or re-issue the certificate (e.g. after pointing a custom domain's DNS). Idempotent. Returns the updated Site.
Set this site's managed-storage (Devani CDN) cap. The account-wide sum of caps can't exceed your plan allowance.
| Field | Type | Notes |
|---|---|---|
limit_mb | integer | Per-site cap in MB. |
Choose which file types the site's media uploader accepts. Images and video are always allowed; pass a list of extra extensions to also allow them (e.g. CAD or document formats), or an empty list to return to images+video only.
| Field | Type | Notes |
|---|---|---|
extensions | string[] | Extra extensions, no dot (e.g. ["rfa","dwg","pdf"]). Max 40. Script/markup types (php, html, svg, js, …) are rejected for security. |
The Devani version this site runs, whether its release feed has something newer, and the backups the install holds (pre-update code backups, daily content snapshots, hourly storage snapshots).
Update the site to the latest Devani release. The install's own updater runs: it backs up the current code first and preserves all content, config, and snapshots. A no-op (`updated: false`) if the site is already current. Response includes `previous_version`, `version`, and the `backup_name` it created.
Enable chrooted SFTP (the password is returned once) or disable it (enabled=false). Re-enabling rotates the password.
If you've connected a Cloudflare token (Account → Automatic DNS), these routes let you
read and manage the DNS on your own Cloudflare account through the same API
you use for everything else — so a provisioning script never has to hold a Cloudflare key.
The token stays server-side and is never returned; you authenticate with your
X-API-Key only.
List the zones (domains) on your Cloudflare account. Optional ?name= filter.
curl https://app.devani.io/api/v1/cloudflare/zones -H "X-API-Key: $KEY"
{ "zones": [ { "id": "abc123", "name": "client.com", "status": "active",
"paused": false, "name_servers": ["..."] } ] }
List DNS records in a zone. Optional ?type= (A, CNAME, TXT…) and ?name= filters. Returns Cloudflare's record objects (id, type, name, content, proxied, ttl).
Create a DNS record.
| Field | Type | Notes |
|---|---|---|
type | string | Required. A, AAAA, CNAME, TXT, MX, … |
name | string | Required. Record name (e.g. www.client.com). |
content | string | Required. The value (IP, target, text). |
proxied | bool | Optional (A/AAAA/CNAME). Default false. |
ttl | integer | Optional. 1 = automatic. |
priority | integer | Optional (MX/SRV). |
curl -X POST https://app.devani.io/api/v1/cloudflare/zones/abc123/dns \
-H "X-API-Key: $KEY" -H "Content-Type: application/json" \
-d '{"type":"A","name":"www.client.com","content":"203.0.113.10","proxied":true}'
Update a record — send only the fields you want to change.
Delete a record by id.
POST /sites → the site is live on its free address.hub_mcp_url) — point Claude at it and build it out.POST /sites/{id}/domains → attach the client's domain; with Cloudflare connected it auto-configures, otherwise add the returned records.{
"id": 12,
"slug": "acme",
"display_name": "Acme Co",
"primary_domain": "www.client.com",
"url": "https://www.client.com",
"site_status": "active",
"has_ssl": true,
"setup_pending": false,
"domains": [ { "id": 31, "name": "acme.devani.studio", "is_primary": false, "ssl": true },
{ "id": 32, "name": "www.client.com", "is_primary": true, "ssl": true } ],
"devani_admin": {
"url": "https://www.client.com/devani/",
"username": "owner",
"password": "shown once at creation",
"mcp_url": "https://www.client.com/devani/mcp/?api_key=..."
},
"custom_domain_setup": []
}
Devani Hosting · app.devani.io