# Porkbun API v3 — Hosting

> Two hosting products share these endpoints — pick one with the `sku` you pass to `/hosting/create`:

• **Secure Static Hosting** — you upload the files; Porkbun serves them over HTTPS. SKUs `PIXIESECURESTATIC…`
• **Cloud for WordPress** — a managed WordPress site; you manage it through WordPress itself. SKUs `CLOUDWORDPRESS…`

Shared by both: `/hosting/plans`, `/hosting/create`, `/hosting/get`, `/hosting/delete`.
Static hosting only: `/hosting/deploy`, `/hosting/files`, `/hosting/makeDir`, `/hosting/deleteFile` (they return `NOT_SUPPORTED_FOR_PRODUCT` on a WordPress site).
WordPress only: `/hosting/createWpCredentials`, `/hosting/getWpCredentials`, `/hosting/deleteWpCredentials`.

Both products: the domain's first provision is a 15-day free trial that auto-renews at the plan price; a re-provision after deprovision is charged (one free trial per domain).

Part of the Porkbun API v3.48. Topic index: https://porkbun.com/llms · Full reference: https://porkbun.com/llms-full.txt · Overview: https://porkbun.com/llms.txt · OpenAPI spec: https://porkbun.com/api/json/v3/spec

**Auth:** send `X-API-Key` / `X-Secret-API-Key` headers (preferred) or `apikey` / `secretapikey` in the JSON body. Create keys at https://porkbun.com/account/api

---

# Endpoints

## GET /api/json/v3/hosting/plans

**List provisionable hosting plans (static + WordPress)**

**Applies to:** Both products.

List the hosting plans that can be provisioned via the API, with price, interval, trial length, and features. Pass a row's `plan` to `/hosting/create` and its `price` (cents) as `acknowledgedCost`. Currently Secure Static Hosting; more products are added over time. Also available via POST. Includes both Secure Static Hosting and Cloud for WordPress (managed WordPress) plans; the `product` field distinguishes them.

```bash
curl https://api.porkbun.com/api/json/v3/hosting/plans \
  -H 'X-API-Key: pk1_...' -H 'X-Secret-API-Key: sk1_...'
```

Response fields:

| Field | Type | Description |
|---|---|---|
| `status` | string |  |
| `plans` | object[] |  |

## POST /api/json/v3/hosting/create/{domain}

**Provision hosting — a static site or a WordPress site**

**Applies to:** Both products — the `sku` decides which.

Provision hosting (Secure Static Hosting or Cloud for WordPress) for a domain in the account. The FIRST provision for a domain starts a **15-day free trial** ($0 now) that **auto-renews** at the plan price when the trial ends; a re-provision after deprovision is charged immediately to account credit (one free trial per domain). Provisioning **switches the domain to Porkbun nameservers** if it isn't already — pass `agreeToNameserverChange: true` to allow that. Supports `dryRun`. Remote setup can be async: `status` may be `PENDING` — poll `/hosting/get` until `ACTIVE` before deploying.

**Cloud for WordPress:** pass a `CLOUDWORDPRESS…` sku to provision a managed WordPress site instead of static hosting. The file endpoints (deploy/files/deleteFile/makeDir) do not apply — manage the site through WordPress, using `/hosting/createWpCredentials/{domain}` for REST API credentials.

**Rate limit:** 10 provisions per account per hour (`dryRun` calls are free).

| Parameter | In | Required | Description |
|---|---|---|---|
| `domain` | path | yes |  |

Request body fields:

| Field | Type | Required | Description |
|---|---|---|---|
| `sku` | string | yes | The hosting plan SKU to provision. Discover the provisionable SKUs (and each one’s price/interval/trial) via GET /hosting/plans, then pass the row’s `sku`. Currently Secure Static Hosting: PIXIESECURESTATICM2 ($3.00/mo) or PIXIESECURESTATICY2 ($30.00/yr). |
| `acknowledgedCost` | integer | yes | Echo the plan price in cents (300 monthly / 3000 yearly) to confirm the account holder understands the auto-renew / charge. Mismatch returns COST_ACKNOWLEDGMENT_REQUIRED. |
| `agreeToTerms` | string | yes |  |
| `agreeToNameserverChange` | boolean | no | Required (true) when the domain is not already on Porkbun nameservers — provisioning will switch them. |
| `dryRun` | boolean | no | Validate + preview without provisioning or charging. |

```bash
curl -X POST https://api.porkbun.com/api/json/v3/hosting/create/example.com \
  -H 'Content-Type: application/json' \
  -d '{"apikey":"pk1_...","secretapikey":"sk1_...","plan":"monthly","acknowledgedCost":300,"agreeToTerms":"yes"}'
```

Response fields:

| Field | Type | Description |
|---|---|---|
| `status` | string |  |
| `orderId` | integer |  |
| `hosting` | object |  |
| `charged` | integer | Cents captured now (0 on the free trial). |
| `cost` | object |  |
| `message` | string |  |

## GET /api/json/v3/hosting/get/{domain}

**Get hosting status (either product)**

**Applies to:** Both products.

Return the Secure Static Hosting status for a domain (plan, server, trial, expiry, auto-renew), or `hosting: null` if none. Also available via POST.

| Parameter | In | Required | Description |
|---|---|---|---|
| `domain` | path | yes |  |

```bash
curl https://api.porkbun.com/api/json/v3/hosting/get/example.com \
  -H 'X-API-Key: pk1_...' -H 'X-Secret-API-Key: sk1_...'
```

Response fields:

| Field | Type | Description |
|---|---|---|
| `status` | string |  |
| `hosting` | object |  |

## POST /api/json/v3/hosting/deploy/{domain}

**Upload site files (static hosting only)**

**Applies to:** Secure Static Hosting only — a WordPress site returns `NOT_SUPPORTED_FOR_PRODUCT`; manage its content through WordPress instead.

Upload static files to the domain's Secure Static Hosting space. Send `files` as an array of `{ path, content }` where `content` is base64. Total payload ≤ 10 MB per request (split larger sites across calls). Only static-web file types are accepted (html/css/js/images/fonts/…); server-executable types are rejected. Hosting must be ACTIVE. A file’s `path` may include directories (e.g. `assets/css/style.css`); any missing parent directories are created automatically. Paths are sanitized (no traversal/control chars) and the filename extension must be an allowed static-web type.

| Parameter | In | Required | Description |
|---|---|---|---|
| `domain` | path | yes |  |

Request body fields:

| Field | Type | Required | Description |
|---|---|---|---|
| `files` | object[] | yes |  |

```bash
curl -X POST https://api.porkbun.com/api/json/v3/hosting/deploy/example.com \
  -H 'Content-Type: application/json' \
  -d '{"apikey":"pk1_...","secretapikey":"sk1_...","files":[{"path":"index.html","content":"PGgxPkhlbGxvPC9oMT4="}]}'
```

Response fields:

| Field | Type | Description |
|---|---|---|
| `status` | string |  |
| `deployed` | string[] |  |
| `skipped` | object[] |  |

## GET /api/json/v3/hosting/files/{domain}

**List site files (static hosting only)**

**Applies to:** Secure Static Hosting only — a WordPress site returns `NOT_SUPPORTED_FOR_PRODUCT`.

List file/directory names under an optional `path` in the domain's hosting space. Also available via POST (send `path` in the body).

| Parameter | In | Required | Description |
|---|---|---|---|
| `domain` | path | yes |  |

Response fields:

| Field | Type | Description |
|---|---|---|
| `status` | string |  |
| `path` | string |  |
| `files` | string[] |  |

## POST /api/json/v3/hosting/deleteFile/{domain}

**Delete a site file (static hosting only)**

**Applies to:** Secure Static Hosting only — a WordPress site returns `NOT_SUPPORTED_FOR_PRODUCT`.

Delete a file (or empty directory) at `path` in the domain's hosting space.

| Parameter | In | Required | Description |
|---|---|---|---|
| `domain` | path | yes |  |

Request body fields:

| Field | Type | Required | Description |
|---|---|---|---|
| `path` | string | yes |  |

Response fields:

| Field | Type | Description |
|---|---|---|
| `status` | string |  |
| `deleted` | string |  |

## POST /api/json/v3/hosting/delete/{domain}

**Deprovision hosting (either product)**

**Applies to:** Both products.

Deprovision (cancel) Secure Static Hosting for a domain; teardown is scheduled and completed by Porkbun. Note: the domain has already used its one free trial, so provisioning it again later will be charged (no second free trial).

| Parameter | In | Required | Description |
|---|---|---|---|
| `domain` | path | yes |  |

Response fields (BasicResponse):

| Field | Type | Description |
|---|---|---|
| `warnings` | string[] | Advisory, and present only when there is something to say. It never means the call failed. The one to handle: a DNS write is accepted and stored even when the domain is NOT delegated to our nameservers -- we keep the zone ready in case the delegation comes back -- so the write changed nothing that resolves, and this field says so. Show these to the user as written. |
| `status` | string |  |
| `message` | string | Human-readable message. Present on ERROR, sometimes on SUCCESS. |
| `code` | string | Machine-readable error code. Present when status is ERROR. |

## POST /api/json/v3/hosting/makeDir/{domain}

**Create a directory (static hosting only)**

**Applies to:** Secure Static Hosting only — a WordPress site returns `NOT_SUPPORTED_FOR_PRODUCT`.

Create a directory (and any missing parent directories) at `path` in the domain’s hosting space. Deploy already auto-creates directories in a file’s path, so use this to stand up an empty directory explicitly. Path is sanitized segment-by-segment (no traversal / control chars).

| Parameter | In | Required | Description |
|---|---|---|---|
| `domain` | path | yes |  |

Request body fields:

| Field | Type | Required | Description |
|---|---|---|---|
| `path` | string | yes |  |

Response fields:

| Field | Type | Description |
|---|---|---|
| `status` | string |  |
| `created` | string |  |

## POST /api/json/v3/hosting/createWpCredentials/{domain}

**Mint WordPress REST API credentials (WordPress only)**

**Applies to:** Cloud for WordPress only.

Creates a WordPress **Application Password** so an agent or integration can drive the site over the WP REST API at `https://{domain}/wp-json/` using HTTP Basic auth. The password is returned **once** — WordPress stores only a hash.

Defaults to a dedicated least-privilege `porkbun-agent` user with the `editor` role (created on first use), which can manage content but not install code. `role: "administrator"` grants full site control **including plugin installation (arbitrary code execution on the site)** and therefore requires `acknowledgeFullAccess: true`.

Revoke any time via `/hosting/deleteWpCredentials/{domain}` or in wp-admin under Users → Profile. Requires the site to be provisioned and ACTIVE (poll `/hosting/get/{domain}`).

Free **preview** sites (the $0 parked plan) are excluded — they return `PREVIEW_SITE_NOT_SUPPORTED`; upgrade to a paid plan first. Works on any Cloud for WordPress site in the account regardless of whether it was provisioned via the API or the website, including sites migrated onto WP Cloud from the legacy WordPress product. For `role: "administrator"` the site's actual administrator account is looked up rather than assumed, so a renamed admin user is handled.

**Rate limit:** 20 mints per account per hour (`dryRun` calls are free).

| Parameter | In | Required | Description |
|---|---|---|---|
| `domain` | path | yes |  |

Request body fields:

| Field | Type | Required | Description |
|---|---|---|---|
| `role` | string | no | Least privilege by default. `editor` = content only (recommended for agents). `administrator` = full control incl. plugin install; requires acknowledgeFullAccess. |
| `acknowledgeFullAccess` | boolean | no | Required when role=administrator: confirms you understand the credential can run arbitrary code on the site. |
| `name` | string | no | Label shown in wp-admin (sanitized to letters, digits and dashes). |
| `dryRun` | boolean | no | Validate without creating anything. |

Response fields:

| Field | Type | Description |
|---|---|---|
| `status` | string |  |
| `credentials` | object |  |
| `message` | string |  |

## GET /api/json/v3/hosting/getWpCredentials/{domain}

**List WordPress application passwords (WordPress only)**

**Applies to:** Cloud for WordPress only.

Lists the application passwords on the site (uuid, name, created, last used) so you can audit or pick one to revoke. Metadata only — WordPress stores just a hash, so a password can never be re-read. Optional `wpUser` (defaults to the dedicated `porkbun-agent` user).

Free preview sites are excluded (`PREVIEW_SITE_NOT_SUPPORTED`).

| Parameter | In | Required | Description |
|---|---|---|---|
| `domain` | path | yes |  |
| `wpUser` | query | no |  |

Response fields:

| Field | Type | Description |
|---|---|---|
| `status` | string |  |
| `wpUser` | string |  |
| `credentials` | object[] |  |

## POST /api/json/v3/hosting/deleteWpCredentials/{domain}

**Revoke WordPress application passwords (WordPress only)**

**Applies to:** Cloud for WordPress only.

Revokes an application password by `uuid` (from `/hosting/getWpCredentials`), or every one for the user with `all: true`. Any integration using it stops authenticating immediately.

Free preview sites are excluded (`PREVIEW_SITE_NOT_SUPPORTED`).

| Parameter | In | Required | Description |
|---|---|---|---|
| `domain` | path | yes |  |

Request body fields:

| Field | Type | Required | Description |
|---|---|---|---|
| `uuid` | string | no | The application password uuid to revoke. |
| `all` | boolean | no | Revoke every application password for the user. |
| `wpUser` | string | no |  |
| `dryRun` | boolean | no |  |

Response fields:

| Field | Type | Description |
|---|---|---|
| `status` | string |  |
| `revoked` | string |  |
| `message` | string |  |

---

## More

- Guides (how-tos): https://porkbun.com/llms/guides
- Topic index: https://porkbun.com/llms
- Full reference (one file): https://porkbun.com/llms-full.txt
- OpenAPI spec (full schemas): https://porkbun.com/api/json/v3/spec
- Short overview: https://porkbun.com/llms.txt
- Official MCP server: https://porkbun.com/mcp (`npx -y @porkbunllc/mcp-server`)
- Create API keys: https://porkbun.com/account/api
