# Build a Link in Bio page

A Link in Bio page is a single page of links on a domain: a title, a short
bio, an avatar, a list of buttons, and social icons. It is what goes in an
Instagram or TikTok profile. Everything the editor on porkbun.com does can be
done over the API, and the page and the editor show every change at once.

Reading a page needs a key with the `read` permission; editing needs
`hosting`. The domain must be opted in to API access. Sandbox keys can't use
these endpoints.

## 1. See what the domain already has

Most .com domains registered at Porkbun come with a free page, so look first:

```
GET /api/json/v3/linkinbio/get/example.com
```

`LINKINBIO_NOT_FOUND` means there is no page yet (step 2). Otherwise the
response describes the page:

- `url`: where it lives. `delivery: "domain"` means it is served on the domain
  itself; `delivery: "l.ink"` means the domain forwards to
  `https://example-com.l.ink` (the free page that ships with .com
  registrations).
- `plan` and `features`: what the plan allows.
- `links`: every entry in display order, each with an `id` you use to edit it.

## 2. Turn one on, free or paid

**Free:**

```
POST /api/json/v3/linkinbio/create/example.com
{"apikey": "pk1_...", "secretapikey": "sk1_..."}
```

This creates a page served on the domain, with up to 50 links. It starts with
a placeholder title, bio and link, so replace them (step 3). The domain is
pointed at the page with DNS records, which needs Porkbun nameservers. If the
domain uses other ones, the call returns `NAMESERVER_CHANGE_REQUIRED`: ask
the person, then send `"agreeToNameserverChange": true`. A free WordPress
preview on the domain is replaced; real hosting is not
(`HOSTING_ALREADY_EXISTS`).

**Paid:** $3 a month (`PIXIELINKSM1`) or $30 a year (`PIXIELINKSY1`), through
the hosting endpoint:

```
POST /api/json/v3/hosting/create/example.com
{"apikey": "pk1_...", "secretapikey": "sk1_...",
 "sku": "PIXIELINKSY1", "acknowledgedCost": 3000, "agreeToTerms": "yes"}
```

The first paid plan on a domain starts with a 15-day free trial and then
renews at the plan price, so tell the person the price before you buy. Buying
over a free page **upgrades it and keeps everything on it**. Cancelling a paid
plan (`POST /hosting/delete/example.com`) moves the page back to the free
plan; nothing is deleted. To let it lapse at the end of the term instead, turn off
auto-renew: `POST /hosting/updateAutoRenew/example.com` with
`{"autoRenew": false}`.

| | Free on the domain (`PIXIELINKS2M1`) | Free forwarded (`PIXIELINKS2M2`) | Paid |
|---|---|---|---|
| Where | the domain | `<domain>.l.ink` | the domain |
| Links | 50 | 1000 | 1000 |
| Scheduling, animation, passcode protection, analytics IDs, UTM | no | yes | yes |
| Age check, content warning, social icons, appearance | yes | yes | yes |

Asking for a feature the plan lacks returns `FEATURE_NOT_IN_PLAN`, and nothing
in that request is saved.

## 3. Profile

```
POST /api/json/v3/linkinbio/updateProfile/example.com
{"apikey": "...", "secretapikey": "...",
 "title": "Jane Baker", "bio": "Sourdough, every Saturday at the market.",
 "avatar": "data:image/jpeg;base64,/9j/4AAQ..."}
```

Only the fields you send change. `avatar` is a JPEG or PNG, base64, up to 5 MB;
`null` removes it.

## 4. Links

Add one (it goes to the bottom unless you send `"position": "top"`):

```
POST /api/json/v3/linkinbio/addLink/example.com
{"apikey": "...", "secretapikey": "...",
 "title": "Order a loaf", "url": "https://example.com/order"}
```

- `type`: `link` (default), `featured` (shown larger), or `category`, a heading
  that groups the links under it and has no `url`.
- URLs must be web addresses; a bare host like `example.com/shop` gets
  `https://` added.
- Two links can't share both a title and a URL (`DUPLICATE_LINK`).

Change a link with `editLink` (send its `id` and only what changes). To hide a
link without losing it, send `"enabled": false`. `deleteLink` removes it for
good, with its image and settings.

Reorder by sending every id in the new order:

```
POST /api/json/v3/linkinbio/reorderLinks/example.com
{"apikey": "...", "secretapikey": "...", "ids": [1292106, 1292105, 1275452]}
```

On a plan that allows them, links can also take:

- `startDate` / `endDate`: show the link only within that window. A date or
  ISO 8601 time, UTC unless you give an offset.
- `animation`: `pulse`, `bounce` or `shake`, to draw the eye.
- `protection`: `{"type": "code", "value": "1234"}` asks visitors for a
  passcode. `{"type": "birthday", "value": "21"}` asks them to confirm their
  age, and `{"type": "sensitive"}` shows a content warning; those two work on
  every plan.

## 5. Socials, look and settings

```
POST /api/json/v3/linkinbio/updateSocials/example.com
{"apikey": "...", "secretapikey": "...", "location": "bottom",
 "socials": {"instagram": "janebakes", "email": "jane@example.com"}}
```

```
POST /api/json/v3/linkinbio/updateAppearance/example.com
{"apikey": "...", "secretapikey": "...",
 "preset": "paper", "fontFamily": "lora", "buttonStyle": "pill", "radius": 18}
```

`preset` (classic, ocean, midnight, paper, forest, sunset) is a ready-made look;
the colours (`pageBackgroundColor`, `pageBackgroundColor2` with
`pageBackgroundMode: "gradient"`, `pageColor`, `boxBackgroundColor`,
`borderColor`, as hex) fine-tune it. `null` resets a value to the default.

`updateSettings` sets `sensitiveContent` (a `generic` warning, or an age check
of `18`, `21` or `25`, before the whole page) and, on paid plans, analytics
tracking IDs and UTM parameters. A mailing-list signup form is set up in the
editor on porkbun.com only.

## From the MCP server

The tools are `get_link_in_bio`, `create_link_in_bio`, `update_link_in_bio_profile`,
`add_link_in_bio_link`, `edit_link_in_bio_link`, `delete_link_in_bio_link`,
`reorder_link_in_bio_links`, `update_link_in_bio_socials`,
`update_link_in_bio_appearance` and `update_link_in_bio_settings`. Paid plans are
bought with `create_hosting` (not on the ChatGPT directory connector, which
does not sell anything).

## Errors

- `LINKINBIO_NOT_FOUND`: no page on the domain; create one.
- `LINKINBIO_ALREADY_EXISTS`: there is already a page; edit it instead.
- `FEATURE_NOT_IN_PLAN`: the free plan lacks that feature; nothing was saved.
- `LINK_LIMIT_REACHED`: 50 links on the free plan, 1000 on paid ones.
- `LINK_NOT_FOUND`: use an `id` from `get`.
- `NAMESERVER_CHANGE_REQUIRED`: the page needs Porkbun nameservers; ask, then
  resend with `agreeToNameserverChange: true`.


---

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