# Porkbun API v3 — Link in Bio

> A Link in Bio page: a single page of links, served on the domain (or, for the free plan that comes with .com registrations, forwarded to `<domain>.l.ink`). Edits made here show up immediately in the page and in the editor on porkbun.com.

• **Turn one on:** free with `/linkinbio/create` (50 links), or paid with `/hosting/create` and sku `PIXIELINKSM1` ($3/month) or `PIXIELINKSY1` ($30/year) for 1000 links plus scheduling, animation, passcode protection and analytics IDs. Buying a paid plan over a free page keeps its content. Cancelling a paid plan (`/hosting/delete`) moves the page back to the free plan; nothing is deleted.
• **Edit it:** `get` returns everything with link ids; then `updateProfile`, `addLink`, `editLink`, `deleteLink`, `reorderLinks`, `updateSocials`, `updateAppearance`, `updateSettings`. Reading needs the `read` permission, editing `hosting`.

Not available with sandbox keys.

Part of the Porkbun API v3.68. 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/linkinbio/get/{domain}

**Get a Link in Bio page**

The page on a domain: its public URL, plan and what the plan allows, profile, links in display order (with ids), social icons, appearance and settings. Use it before editing, and to read link ids.

**Errors:** `LINKINBIO_NOT_FOUND` (no page; the message says what the domain has instead).

**Key permission needed:** `read`

| Parameter | In | Required | Description |
|---|---|---|---|
| `domain` | path | yes |  |
| `Idempotency-Key` | header | no | Optional, recommended on every purchase and write. Send a unique value (a UUID) per intended operation. Repeating the request with the same key and an identical body within 24 hours returns the original response instead of doing it again, so a retry after a timeout cannot double-charge or double-apply. The same key with a different body returns 409 IDEMPOTENCY_KEY_MISMATCH; while the first request is still running, 409 IDEMPOTENCY_KEY_IN_USE. |
| `X-API-Key` | header | no |  |
| `X-Secret-API-Key` | header | no |  |

Response fields (LinkInBioResponse):

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

## POST /api/json/v3/linkinbio/get/{domain}

**Get a Link in Bio page**

The page on a domain: its public URL, plan and what the plan allows, profile, links in display order (with ids), social icons, appearance and settings. Use it before editing, and to read link ids.

**Errors:** `LINKINBIO_NOT_FOUND` (no page; the message says what the domain has instead).

**Key permission needed:** `read`

| Parameter | In | Required | Description |
|---|---|---|---|
| `domain` | path | yes |  |
| `Idempotency-Key` | header | no | Optional, recommended on every purchase and write. Send a unique value (a UUID) per intended operation. Repeating the request with the same key and an identical body within 24 hours returns the original response instead of doing it again, so a retry after a timeout cannot double-charge or double-apply. The same key with a different body returns 409 IDEMPOTENCY_KEY_MISMATCH; while the first request is still running, 409 IDEMPOTENCY_KEY_IN_USE. |
| `Idempotency-Key` | header | no | Optional, recommended on every purchase and write. Send a unique value (a UUID) per intended operation. Repeating the request with the same key and an identical body within 24 hours returns the original response instead of doing it again, so a retry after a timeout cannot double-charge or double-apply. The same key with a different body returns 409 IDEMPOTENCY_KEY_MISMATCH; while the first request is still running, 409 IDEMPOTENCY_KEY_IN_USE. |

Response fields (LinkInBioResponse):

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

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

**Turn on a free Link in Bio page**

Turns on a free page served on the domain itself (plan PIXIELINKS2M1: up to 50 links; no scheduling, animation, passcode protection or analytics IDs). Free, nothing is ordered. It starts with a placeholder title, bio and link: replace them with `updateProfile`, `editLink` and `addLink`.

The domain is pointed at the page with DNS records, which needs Porkbun nameservers: if the domain uses other ones, send `agreeToNameserverChange: true` to switch them. A free WordPress preview on the domain is replaced; any other hosting is not (`HOSTING_ALREADY_EXISTS`).

Many .com domains registered at Porkbun already have a free page, forwarded to `<domain>.l.ink`; check with `get` first. For a paid plan (1000 links, every feature), use `/hosting/create` with sku `PIXIELINKSM1` or `PIXIELINKSY1`: it upgrades an existing free page and keeps its content. Supports `dryRun`. Not available with sandbox keys.

**Errors:** `LINKINBIO_ALREADY_EXISTS`, `HOSTING_ALREADY_EXISTS`, `NAMESERVER_CHANGE_REQUIRED`, `LINKINBIO_CREATE_FAILED`.

**Key permission needed:** `hosting`

| Parameter | In | Required | Description |
|---|---|---|---|
| `domain` | path | yes |  |
| `Idempotency-Key` | header | no | Optional, recommended on every purchase and write. Send a unique value (a UUID) per intended operation. Repeating the request with the same key and an identical body within 24 hours returns the original response instead of doing it again, so a retry after a timeout cannot double-charge or double-apply. The same key with a different body returns 409 IDEMPOTENCY_KEY_MISMATCH; while the first request is still running, 409 IDEMPOTENCY_KEY_IN_USE. |

Request body fields:

| Field | Type | Required | Description |
|---|---|---|---|
| `agreeToNameserverChange` | boolean | no | Required when the domain is not on Porkbun nameservers. |

Response fields (LinkInBioResponse):

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

## POST /api/json/v3/linkinbio/updateProfile/{domain}

**Update the page title, bio and avatar**

Only the fields sent change; an empty title or bio removes it. `avatar` is a base64 JPEG or PNG (a `data:` URL works too), up to 5 MB and 4000x4000; null removes it. Supports `dryRun`. Not available with sandbox keys.

**Errors:** `INVALID_INPUT`, `LINKINBIO_SAVE_FAILED`.

**Key permission needed:** `hosting`

| Parameter | In | Required | Description |
|---|---|---|---|
| `domain` | path | yes |  |
| `Idempotency-Key` | header | no | Optional, recommended on every purchase and write. Send a unique value (a UUID) per intended operation. Repeating the request with the same key and an identical body within 24 hours returns the original response instead of doing it again, so a retry after a timeout cannot double-charge or double-apply. The same key with a different body returns 409 IDEMPOTENCY_KEY_MISMATCH; while the first request is still running, 409 IDEMPOTENCY_KEY_IN_USE. |

Request body fields:

| Field | Type | Required | Description |
|---|---|---|---|
| `title` | string | no | Up to 100 characters. |
| `bio` | string | no | Up to 500 characters. |
| `avatar` | string | no | Base64 JPEG or PNG, or null to remove. |

Response fields (LinkInBioResponse):

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

## POST /api/json/v3/linkinbio/addLink/{domain}

**Add a link**

Adds a link, featured link or category heading. `position`: `bottom` (default) or `top`. Returns the new link (with its id) and the page. Fields marked "paid plans" return `FEATURE_NOT_IN_PLAN` on the free on-domain plan, and nothing is saved. Supports `dryRun`. Not available with sandbox keys.

**Errors:** `LINK_LIMIT_REACHED`, `DUPLICATE_LINK` (same title and URL as another link), `FEATURE_NOT_IN_PLAN`, `INVALID_INPUT`.

**Key permission needed:** `hosting`

| Parameter | In | Required | Description |
|---|---|---|---|
| `domain` | path | yes |  |
| `Idempotency-Key` | header | no | Optional, recommended on every purchase and write. Send a unique value (a UUID) per intended operation. Repeating the request with the same key and an identical body within 24 hours returns the original response instead of doing it again, so a retry after a timeout cannot double-charge or double-apply. The same key with a different body returns 409 IDEMPOTENCY_KEY_MISMATCH; while the first request is still running, 409 IDEMPOTENCY_KEY_IN_USE. |

Request body fields:

| Field | Type | Required | Description |
|---|---|---|---|
| `type` | string | no | `link` (default), `featured` or `category` (a heading; no url). |
| `title` | string | yes | Up to 255 characters. |
| `url` | string | no | http(s) address, up to 255 characters; a bare host gets https:// added. Not for a category. |
| `enabled` | boolean | no | Default true. |
| `startDate` | string | no | Show from this time: YYYY-MM-DD, or ISO 8601; UTC unless an offset is given. null clears it. Paid plans. |
| `endDate` | string | no | Hide after this time; same format. Paid plans. |
| `animation` | string | no | `pulse`, `bounce`, `shake`, or null for none. Paid plans. |
| `protection` | object | no | null removes it. `code` (passcode; paid plans) needs value; `birthday` takes value 18, 21 or 25; `sensitive` shows a warning. |
| `position` | string | no |  |

Response fields (LinkInBioLinkResponse):

| Field | Type | Description |
|---|---|---|
| `status` | string |  |
| `link` | object | One entry on the page, in display order. |
| `linkInBio` | object |  |

## POST /api/json/v3/linkinbio/editLink/{domain}

**Edit a link**

Changes any of a link's fields; `id` is required and only the fields sent change. Set `enabled: false` to hide a link without deleting it. Supports `dryRun`. Not available with sandbox keys.

**Errors:** `LINK_NOT_FOUND`, `DUPLICATE_LINK`, `FEATURE_NOT_IN_PLAN`, `INVALID_INPUT`.

**Key permission needed:** `hosting`

| Parameter | In | Required | Description |
|---|---|---|---|
| `domain` | path | yes |  |
| `Idempotency-Key` | header | no | Optional, recommended on every purchase and write. Send a unique value (a UUID) per intended operation. Repeating the request with the same key and an identical body within 24 hours returns the original response instead of doing it again, so a retry after a timeout cannot double-charge or double-apply. The same key with a different body returns 409 IDEMPOTENCY_KEY_MISMATCH; while the first request is still running, 409 IDEMPOTENCY_KEY_IN_USE. |

Request body fields:

| Field | Type | Required | Description |
|---|---|---|---|
| `type` | string | no | `link` (default), `featured` or `category` (a heading; no url). |
| `title` | string | no | Up to 255 characters. |
| `url` | string | no | http(s) address, up to 255 characters; a bare host gets https:// added. Not for a category. |
| `enabled` | boolean | no | Default true. |
| `startDate` | string | no | Show from this time: YYYY-MM-DD, or ISO 8601; UTC unless an offset is given. null clears it. Paid plans. |
| `endDate` | string | no | Hide after this time; same format. Paid plans. |
| `animation` | string | no | `pulse`, `bounce`, `shake`, or null for none. Paid plans. |
| `protection` | object | no | null removes it. `code` (passcode; paid plans) needs value; `birthday` takes value 18, 21 or 25; `sensitive` shows a warning. |
| `id` | integer | yes | From `get`. |

Response fields (LinkInBioLinkResponse):

| Field | Type | Description |
|---|---|---|
| `status` | string |  |
| `link` | object | One entry on the page, in display order. |
| `linkInBio` | object |  |

## POST /api/json/v3/linkinbio/deleteLink/{domain}

**Delete a link**

Deletes a link with its image, animation and protection. To hide a link instead, use editLink with `enabled: false`. Supports `dryRun`. Not available with sandbox keys.

**Errors:** `LINK_NOT_FOUND`.

**Key permission needed:** `hosting`

| Parameter | In | Required | Description |
|---|---|---|---|
| `domain` | path | yes |  |
| `Idempotency-Key` | header | no | Optional, recommended on every purchase and write. Send a unique value (a UUID) per intended operation. Repeating the request with the same key and an identical body within 24 hours returns the original response instead of doing it again, so a retry after a timeout cannot double-charge or double-apply. The same key with a different body returns 409 IDEMPOTENCY_KEY_MISMATCH; while the first request is still running, 409 IDEMPOTENCY_KEY_IN_USE. |

Request body fields:

| Field | Type | Required | Description |
|---|---|---|---|
| `id` | integer | yes | From `get`. |

Response fields (LinkInBioResponse):

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

## POST /api/json/v3/linkinbio/reorderLinks/{domain}

**Reorder links**

`ids` lists every link id on the page, once each, in the order to show them. Supports `dryRun`. Not available with sandbox keys.

**Errors:** `INVALID_INPUT` (the message lists the current ids).

**Key permission needed:** `hosting`

| Parameter | In | Required | Description |
|---|---|---|---|
| `domain` | path | yes |  |
| `Idempotency-Key` | header | no | Optional, recommended on every purchase and write. Send a unique value (a UUID) per intended operation. Repeating the request with the same key and an identical body within 24 hours returns the original response instead of doing it again, so a retry after a timeout cannot double-charge or double-apply. The same key with a different body returns 409 IDEMPOTENCY_KEY_MISMATCH; while the first request is still running, 409 IDEMPOTENCY_KEY_IN_USE. |

Request body fields:

| Field | Type | Required | Description |
|---|---|---|---|
| `ids` | integer[] | yes | Every link id, in display order. |

Response fields (LinkInBioResponse):

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

## POST /api/json/v3/linkinbio/updateSocials/{domain}

**Update social icons**

`location` (`top` or `bottom`) and `socials`, an object of email, instagram, facebook, tiktok, youtube, twitter and linkedin: a handle or a profile URL. Only the keys sent change; "" or null removes one. Supports `dryRun`. Not available with sandbox keys.

**Errors:** `INVALID_INPUT`.

**Key permission needed:** `hosting`

| Parameter | In | Required | Description |
|---|---|---|---|
| `domain` | path | yes |  |
| `Idempotency-Key` | header | no | Optional, recommended on every purchase and write. Send a unique value (a UUID) per intended operation. Repeating the request with the same key and an identical body within 24 hours returns the original response instead of doing it again, so a retry after a timeout cannot double-charge or double-apply. The same key with a different body returns 409 IDEMPOTENCY_KEY_MISMATCH; while the first request is still running, 409 IDEMPOTENCY_KEY_IN_USE. |

Request body fields:

| Field | Type | Required | Description |
|---|---|---|---|
| `location` | string | no |  |
| `socials` | object | no |  |

Response fields (LinkInBioResponse):

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

## POST /api/json/v3/linkinbio/updateAppearance/{domain}

**Update the page appearance**

Only the keys sent change; null resets one to the editor default. `preset` applies a ready-made look in the editor; set individual colours to fine-tune. Supports `dryRun`. Not available with sandbox keys.

**Errors:** `INVALID_INPUT`.

**Key permission needed:** `hosting`

| Parameter | In | Required | Description |
|---|---|---|---|
| `domain` | path | yes |  |
| `Idempotency-Key` | header | no | Optional, recommended on every purchase and write. Send a unique value (a UUID) per intended operation. Repeating the request with the same key and an identical body within 24 hours returns the original response instead of doing it again, so a retry after a timeout cannot double-charge or double-apply. The same key with a different body returns 409 IDEMPOTENCY_KEY_MISMATCH; while the first request is still running, 409 IDEMPOTENCY_KEY_IN_USE. |

Request body fields:

| Field | Type | Required | Description |
|---|---|---|---|
| `preset` | string | no |  |
| `fontFamily` | string | no |  |
| `buttonStyle` | string | no |  |
| `radius` | integer | no | Button corner radius in pixels, 0-50. |
| `pageBackgroundMode` | string | no | `gradient` blends pageBackgroundColor into pageBackgroundColor2. |
| `textAlign` | string | no |  |
| `pageBackgroundColor` | string | no | Hex colour, e.g. #1b5a8a. |
| `pageBackgroundColor2` | string | no | Hex colour, e.g. #1b5a8a. |
| `pageColor` | string | no | Hex colour, e.g. #1b5a8a. |
| `boxBackgroundColor` | string | no | Hex colour, e.g. #1b5a8a. |
| `borderColor` | string | no | Hex colour, e.g. #1b5a8a. |

Response fields (LinkInBioResponse):

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

## POST /api/json/v3/linkinbio/updateSettings/{domain}

**Update page settings**

`sensitiveContent`: a warning (`generic`) or an age check (`18`, `21`, `25`) shown before the page, or null to turn it off. `analytics`: tracking IDs (googleAnalyticsId, facebookPixelId, twitterPixelId, tikTokPixelId) and UTM parameters (utmSource, utmMedium) added to outgoing links; paid plans; "" removes one. The mailing-list signup form is set up in the editor only. Supports `dryRun`. Not available with sandbox keys.

**Errors:** `FEATURE_NOT_IN_PLAN`, `INVALID_INPUT`.

**Key permission needed:** `hosting`

| Parameter | In | Required | Description |
|---|---|---|---|
| `domain` | path | yes |  |
| `Idempotency-Key` | header | no | Optional, recommended on every purchase and write. Send a unique value (a UUID) per intended operation. Repeating the request with the same key and an identical body within 24 hours returns the original response instead of doing it again, so a retry after a timeout cannot double-charge or double-apply. The same key with a different body returns 409 IDEMPOTENCY_KEY_MISMATCH; while the first request is still running, 409 IDEMPOTENCY_KEY_IN_USE. |

Request body fields:

| Field | Type | Required | Description |
|---|---|---|---|
| `sensitiveContent` | string | no |  |
| `analytics` | object | no |  |

Response fields (LinkInBioResponse):

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

---

## More

- Guides (how-tos): https://porkbun.com/llms/guides
- Help articles (knowledge base) as Markdown: https://porkbun.com/llms/kb
- 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
