# Porkbun API v3 — Porkbun DNS

> Create, read, update and delete DNS records in **Porkbun's** nameservers, including DNSSEC.

These endpoints manage the zone Porkbun serves. If a domain has been moved to a customer's own Cloudflare account (see the **Cloudflare** section), Cloudflare's nameservers answer for it instead — writes here still succeed and are kept in step in case the move is rolled back, but they do not change what resolves, and every response says so in `warnings`. Manage those domains with `/cloudflare/getRecords`, `/cloudflare/createRecord`, `/cloudflare/editRecord` and `/cloudflare/deleteRecord`.

The same is true, more bluntly, of a domain delegated to any other DNS provider: we hold a zone for every domain in the account, so a write always succeeds locally. Whenever the nameservers answering for the domain are not ours, the write response carries a `warnings` string saying so and naming them. Check `warnings` on every write; `GET /dns/preflight/{domain}` reports the same thing (`nameservers-ours`) before you start.

Part of the Porkbun API v3.34. 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

## POST /api/json/v3/dns/retrieve/{domain}

**Retrieve all DNS records**

Retrieve all editable DNS records for a domain. SOA records and Porkbun default NS records are excluded. Supports both GET (with header auth) and POST (with body or header auth).

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

```bash
curl -X POST https://api.porkbun.com/api/json/v3/dns/retrieve/{domain} \
  -H 'Content-Type: application/json' \
  -d '{"apikey":"pk1_...","secretapikey":"sk1_..."}'
```

Response fields (DnsRecordsResponse):

| Field | Type | Description |
|---|---|---|
| `status` | string |  |
| `cloudflare` | string | Whether Cloudflare proxy is enabled for this domain |
| `records` | object[] |  |

## GET /api/json/v3/dns/retrieve/{domain}

**Retrieve all DNS records**

Retrieve all editable DNS records for a domain. SOA records and Porkbun default NS records are excluded. Supports both GET (with header auth) and POST (with body or header auth).

| Parameter | In | Required | Description |
|---|---|---|---|
| `domain` | path | yes |  |
| `Authorization` | header | no | Bearer token auth: `Authorization: Bearer <token>` |
| `X-API-Key` | header | no | API key header auth (use with X-Secret-API-Key) |
| `X-Secret-API-Key` | header | no | Secret API key header auth (use with X-API-Key) |

```bash
curl 'https://api.porkbun.com/api/json/v3/dns/retrieve/{domain}' \
  -H 'X-API-Key: pk1_...' \
  -H 'X-Secret-API-Key: sk1_...'
```

Response fields (DnsRecordsResponse):

| Field | Type | Description |
|---|---|---|
| `status` | string |  |
| `cloudflare` | string | Whether Cloudflare proxy is enabled for this domain |
| `records` | object[] |  |

## POST /api/json/v3/dns/retrieve/{domain}/{id}

**Retrieve DNS record by ID**

Retrieve a specific DNS record by its numeric ID. Supports both GET (with header auth) and POST (with body or header auth).

| Parameter | In | Required | Description |
|---|---|---|---|
| `domain` | path | yes |  |
| `id` | path | yes | Numeric DNS record ID |

```bash
curl -X POST https://api.porkbun.com/api/json/v3/dns/retrieve/{domain}/{id} \
  -H 'Content-Type: application/json' \
  -d '{"apikey":"pk1_...","secretapikey":"sk1_..."}'
```

Response fields (DnsRecordsResponse):

| Field | Type | Description |
|---|---|---|
| `status` | string |  |
| `cloudflare` | string | Whether Cloudflare proxy is enabled for this domain |
| `records` | object[] |  |

## GET /api/json/v3/dns/retrieve/{domain}/{id}

**Retrieve DNS record by ID**

Retrieve a specific DNS record by its numeric ID. Supports both GET (with header auth) and POST (with body or header auth).

| Parameter | In | Required | Description |
|---|---|---|---|
| `domain` | path | yes |  |
| `id` | path | yes | Numeric DNS record ID |
| `Authorization` | header | no | Bearer token auth: `Authorization: Bearer <token>` |
| `X-API-Key` | header | no | API key header auth (use with X-Secret-API-Key) |
| `X-Secret-API-Key` | header | no | Secret API key header auth (use with X-API-Key) |

```bash
curl 'https://api.porkbun.com/api/json/v3/dns/retrieve/{domain}/{id}' \
  -H 'X-API-Key: pk1_...' \
  -H 'X-Secret-API-Key: sk1_...'
```

Response fields (DnsRecordsResponse):

| Field | Type | Description |
|---|---|---|
| `status` | string |  |
| `cloudflare` | string | Whether Cloudflare proxy is enabled for this domain |
| `records` | object[] |  |

## POST /api/json/v3/dns/retrieveByNameType/{domain}/{type}/{subdomain}

**Retrieve DNS records by name and type**

Retrieve all DNS records for a domain that match a specific subdomain and record type. Omit `subdomain` (or leave the path segment empty) to query the root domain. Supports both GET (with header auth) and POST (with body or header auth).

| Parameter | In | Required | Description |
|---|---|---|---|
| `domain` | path | yes |  |
| `type` | path | yes | DNS record type (A, AAAA, CNAME, MX, TXT, etc.) |
| `subdomain` | path | no | Subdomain portion only. Omit or leave empty for root domain records. |

```bash
curl -X POST https://api.porkbun.com/api/json/v3/dns/retrieveByNameType/{domain}/{type}/{subdomain} \
  -H 'Content-Type: application/json' \
  -d '{"apikey":"pk1_...","secretapikey":"sk1_..."}'
```

Response fields (DnsRecordsResponse):

| Field | Type | Description |
|---|---|---|
| `status` | string |  |
| `cloudflare` | string | Whether Cloudflare proxy is enabled for this domain |
| `records` | object[] |  |

## GET /api/json/v3/dns/retrieveByNameType/{domain}/{type}/{subdomain}

**Retrieve DNS records by name and type**

Retrieve all DNS records for a domain that match a specific subdomain and record type. Omit `subdomain` (or leave the path segment empty) to query the root domain. Supports both GET (with header auth) and POST (with body or header auth).

| Parameter | In | Required | Description |
|---|---|---|---|
| `domain` | path | yes |  |
| `type` | path | yes | DNS record type (A, AAAA, CNAME, MX, TXT, etc.) |
| `subdomain` | path | no | Subdomain portion only. Omit or leave empty for root domain records. |
| `Authorization` | header | no | Bearer token auth: `Authorization: Bearer <token>` |
| `X-API-Key` | header | no | API key header auth (use with X-Secret-API-Key) |
| `X-Secret-API-Key` | header | no | Secret API key header auth (use with X-API-Key) |

```bash
curl 'https://api.porkbun.com/api/json/v3/dns/retrieveByNameType/{domain}/{type}/{subdomain}' \
  -H 'X-API-Key: pk1_...' \
  -H 'X-Secret-API-Key: sk1_...'
```

Response fields (DnsRecordsResponse):

| Field | Type | Description |
|---|---|---|
| `status` | string |  |
| `cloudflare` | string | Whether Cloudflare proxy is enabled for this domain |
| `records` | object[] |  |

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

**Create DNS record**

Create a new DNS record for a domain. The record ID is returned in the response.

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

Request body fields:

| Field | Type | Required | Description |
|---|---|---|---|
| `name` | string | no | Subdomain for the record (e.g. 'www', '*' for wildcard, blank for root). Do not include the domain name itself. |
| `type` | string | yes | DNS record type |
| `content` | string | yes | The record value |
| `ttl` | integer | no | Time to live in seconds. Minimum is determined by account settings (typically 600). Defaults to the account minimum if omitted or 0. |
| `prio` | integer | no | Priority for MX and SRV records. Defaults to 0 if omitted. |
| `notes` | string | no | Optional notes to store with the record (not served in DNS) |
| `dryRun` | boolean | no | If true, validate only — checks ownership/type/permissions and returns wouldSucceed without creating the record. |

```bash
curl -X POST https://api.porkbun.com/api/json/v3/dns/create/{domain} \
  -H 'Content-Type: application/json' \
  -d '{"apikey":"pk1_...","secretapikey":"sk1_...","name":"www","type":"A","content":"1.2.3.4","ttl":600,"prio":10}'
```

Response fields:

| Field | Type | Description |
|---|---|---|
| `status` | string |  |
| `id` | string | The numeric ID of the newly created record |
| `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. |

## POST /api/json/v3/dns/edit/{domain}/{id}

**Edit DNS record by ID**

Edit a specific DNS record by its numeric ID. SOA and default Porkbun NS records cannot be edited.

| Parameter | In | Required | Description |
|---|---|---|---|
| `domain` | path | yes |  |
| `id` | path | yes | Numeric DNS record ID |

Request body fields:

| Field | Type | Required | Description |
|---|---|---|---|
| `name` | string | no | Subdomain for the record. Do not include the domain name itself. |
| `type` | string | yes | DNS record type |
| `content` | string | yes | The record value |
| `ttl` | integer | no | Time to live in seconds (optional) |
| `prio` | integer | no | Priority for MX/SRV records (optional) |
| `notes` | string | no | Notes (optional). Pass empty string to clear notes; omit or pass null to leave unchanged. |

```bash
curl -X POST https://api.porkbun.com/api/json/v3/dns/edit/{domain}/{id} \
  -H 'Content-Type: application/json' \
  -d '{"apikey":"pk1_...","secretapikey":"sk1_...","type":"A","content":"5.6.7.8","ttl":0,"prio":0}'
```

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/dns/editByNameType/{domain}/{type}/{subdomain}

**Edit DNS records by name and type**

Replace the content of all records matching the given subdomain and type. SOA and NS records cannot be edited with this method (use edit by ID instead).

| Parameter | In | Required | Description |
|---|---|---|---|
| `domain` | path | yes |  |
| `type` | path | yes |  |
| `subdomain` | path | no | Subdomain portion only. Omit or leave empty for root domain records. |

Request body fields:

| Field | Type | Required | Description |
|---|---|---|---|
| `content` | string | yes | New record value to set on all matching records |
| `ttl` | integer | no | Time to live in seconds (optional) |
| `prio` | integer | no | Priority (optional) |
| `notes` | string | no | Notes to store with the record (not served in DNS). Pass an empty string to clear existing notes; pass null or omit this field to leave notes unchanged. |

```bash
curl -X POST https://api.porkbun.com/api/json/v3/dns/editByNameType/{domain}/{type}/{subdomain} \
  -H 'Content-Type: application/json' \
  -d '{"apikey":"pk1_...","secretapikey":"sk1_...","content":"5.6.7.8","ttl":0,"prio":0}'
```

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/dns/delete/{domain}/{id}

**Delete DNS record by ID**

Delete a specific DNS record. SOA and default Porkbun NS records cannot be deleted.

| Parameter | In | Required | Description |
|---|---|---|---|
| `domain` | path | yes |  |
| `id` | path | yes | Numeric DNS record ID |

```bash
curl -X POST https://api.porkbun.com/api/json/v3/dns/delete/{domain}/{id} \
  -H 'Content-Type: application/json' \
  -d '{"apikey":"pk1_...","secretapikey":"sk1_..."}'
```

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/dns/deleteByNameType/{domain}/{type}/{subdomain}

**Delete DNS records by name and type**

Delete all DNS records matching the given subdomain and type. SOA and NS records cannot be deleted with this method (use delete by ID instead).

| Parameter | In | Required | Description |
|---|---|---|---|
| `domain` | path | yes |  |
| `type` | path | yes |  |
| `subdomain` | path | no | Subdomain portion only. Omit or leave empty for root domain records. |

```bash
curl -X POST https://api.porkbun.com/api/json/v3/dns/deleteByNameType/{domain}/{type}/{subdomain} \
  -H 'Content-Type: application/json' \
  -d '{"apikey":"pk1_...","secretapikey":"sk1_..."}'
```

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/dns/getDnssecRecords/{domain}

**Get DNSSEC records**

Retrieve DNSSEC records associated with the domain at the registry. Supports both GET (with header auth) and POST (with body or header auth).

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

```bash
curl -X POST https://api.porkbun.com/api/json/v3/dns/getDnssecRecords/{domain} \
  -H 'Content-Type: application/json' \
  -d '{"apikey":"pk1_...","secretapikey":"sk1_..."}'
```

Response fields:

| Field | Type | Description |
|---|---|---|
| `status` | string |  |
| `records` | object | Object keyed by key tag value. Each value is an object containing the DNSSEC data fields. |

## GET /api/json/v3/dns/getDnssecRecords/{domain}

**Get DNSSEC records**

Retrieve DNSSEC records associated with the domain at the registry. Supports both GET (with header auth) and POST (with body or header auth).

| Parameter | In | Required | Description |
|---|---|---|---|
| `domain` | path | yes |  |
| `Authorization` | header | no | Bearer token auth: `Authorization: Bearer <token>` |
| `X-API-Key` | header | no | API key header auth (use with X-Secret-API-Key) |
| `X-Secret-API-Key` | header | no | Secret API key header auth (use with X-API-Key) |

```bash
curl 'https://api.porkbun.com/api/json/v3/dns/getDnssecRecords/{domain}' \
  -H 'X-API-Key: pk1_...' \
  -H 'X-Secret-API-Key: sk1_...'
```

Response fields:

| Field | Type | Description |
|---|---|---|
| `status` | string |  |
| `records` | object | Object keyed by key tag value. Each value is an object containing the DNSSEC data fields. |

## POST /api/json/v3/dns/createDnssecRecord/{domain}

**Create DNSSEC record**

Create a DNSSEC DS or key record at the registry. DNSSEC requirements vary by registry — `keyTag`, `alg`, `digestType`, and `digest` are the minimum required fields. Key data fields are optional and will be omitted if not accepted by the registry.

Algorithm and digest type are validated against the registry's own policy before the request is sent. Registries are retiring the values deprecated by RFC 9904/9905/9906 on different schedules, so what is accepted depends on the TLD: a value one registry has already dropped may still be accepted by another. A value the registry no longer accepts returns `DNSSEC_ALGORITHM_DEPRECATED`; one that still works but is being retired returns `status: SUCCESS` with a `warnings` array. Use algorithm 8 (RSA/SHA-256) or 13 (ECDSA/SHA-256) with digest type 2 (SHA-256) to be accepted everywhere. Existing DNSSEC records keep resolving regardless, and can always be deleted.

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

Request body fields:

| Field | Type | Required | Description |
|---|---|---|---|
| `keyTag` | string | yes | DNSSEC key tag |
| `alg` | string | yes | DS Data algorithm number (e.g. 13 for ECDSA P-256 SHA-256) |
| `digestType` | string | yes | Digest type number (e.g. 2 for SHA-256) |
| `digest` | string | yes | Hex-encoded digest value |
| `maxSigLife` | string | no | Maximum signature lifetime in seconds (optional, registry-specific) |
| `keyDataFlags` | string | no | Key data flags (optional, used when submitting full key data) |
| `keyDataProtocol` | string | no | Key data protocol (optional) |
| `keyDataAlgo` | string | no | Key data algorithm (optional) |
| `keyDataPubKey` | string | no | Key data public key in base64 (optional) |

```bash
curl -X POST https://api.porkbun.com/api/json/v3/dns/createDnssecRecord/{domain} \
  -H 'Content-Type: application/json' \
  -d '{"apikey":"pk1_...","secretapikey":"sk1_...","keyTag":"12345","alg":"13","digestType":"2","digest":"ABCD1234..."}'
```

Response fields:

| Field | Type | Description |
|---|---|---|
| `warnings` | string[] | Present only when a value was accepted but is being retired, e.g. a digest type the registry has announced it will stop accepting. Advisory: the record was created. |
| `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/dns/deleteDnssecRecord/{domain}/{keytag}

**Delete DNSSEC record**

Delete a DNSSEC record from the registry by key tag. Note: most registries delete all records matching the key data, not only the record with the specified key tag.

| Parameter | In | Required | Description |
|---|---|---|---|
| `domain` | path | yes |  |
| `keytag` | path | yes | The DNSSEC key tag value |

```bash
curl -X POST https://api.porkbun.com/api/json/v3/dns/deleteDnssecRecord/{domain}/{keytag} \
  -H 'Content-Type: application/json' \
  -d '{"apikey":"pk1_...","secretapikey":"sk1_..."}'
```

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. |

---

## 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
