Link-in-bio page
One public page per brand for the link in your profiles, with its views and the clicks on each link.
Each brand can have a page at postwire.io/@<slug>, free on every plan: the brand's name, the avatar of a connected account, a short bio, up to 10 links and the connected profiles as icons. The address is 3-30 lowercase letters, digits and hyphens, unique, and not a reserved word (GET /api/bio?check=<slug> says whether one is free). Links are http or https only; each is published as a tracked postwire.io/r/ link, so GET /api/bio returns the clicks on each link and the page's views, all time and the last 30 days, counting people only (link previews and bots are left out). The page carries no script, escapes everything and has a "Report this page" link. "Made with PostWire" sits at the bottom and can be switched off (hide_badge) on paid plans. The page is cached for a minute, so a change shows within about a minute.
The free tools that need no account are at postwire.io/tools.
GET /api/bio: Read a brand's link-in-bio page, its views and each link's clicksPUT /api/bio: Create or update a brand's link-in-bio pageDELETE /api/bio: Remove a brand's link-in-bio page
Read a brand's link-in-bio page, its views and each link's clicks
/api/bioThe brand's page at postwire.io/@<slug> (free on every plan): its settings, the public URL, views (people only: link previews and bots are left out) and clicks per link, all time and the last 30 days. With ?check=<slug>, says whether that address is free and allowed instead. Before the server's bio-page table exists the answer is available: false, code bio_unavailable.
Needs an API key: Authorization: Bearer pw_live_….
Parameters
| Field | Type | Description |
|---|---|---|
brand_id | query, string (uuid) | The brand; default: the account's first brand |
check | query, string | An address to check: { slug, ok, code?, error? } |
Responses
| Status | Means |
|---|---|
200 | { available, brand_id, page: { slug, title, bio, links: [{ label, url }], show_socials, hide_badge, updated_at } | null, url, stats: { views, views_30d, links: [{ label, url, clicks, clicks_30d }] } | null, socials: [{ platform, handle }], avatar_url, can_hide_badge, limits } |
404 | code brand_not_found |
curl "https://postwire.io/api/bio?brand_id=b3f1c2d4-8a9e-4f6b-a1c2-3d4e5f6a7b8c" \
-H "Authorization: Bearer $POSTWIRE_API_KEY"const res = await fetch("https://postwire.io/api/bio?brand_id=b3f1c2d4-8a9e-4f6b-a1c2-3d4e5f6a7b8c", {
method: "GET",
headers: { Authorization: `Bearer ${process.env.POSTWIRE_API_KEY}` },
});
console.log(res.status, await res.json());import os, requests
r = requests.get(
"https://postwire.io/api/bio?brand_id=b3f1c2d4-8a9e-4f6b-a1c2-3d4e5f6a7b8c",
headers={"Authorization": f"Bearer {os.environ['POSTWIRE_API_KEY']}"},
)
print(r.status_code, r.json())Create or update a brand's link-in-bio page
/api/bioFree on every plan. The address is 3-30 lowercase letters, digits and hyphens, unique, and not a reserved word. Up to 10 links, http or https only; each is published as a tracked postwire.io/r/ link so its clicks are counted. "Made with PostWire" can be switched off on paid plans only (on Free the request is saved with it on, and the answer says so in note). Changes show within about a minute.
Needs an API key: Authorization: Bearer pw_live_….
Body (JSON)
| Field | Type | Description |
|---|---|---|
brand_id | string (uuid) | |
slug required | string | postwire.io/@<slug> Up to 30 characters. |
title | string | The name shown; the brand's name when empty Up to 60 characters. |
bio | string | Up to 280 characters. |
links | array of object | Up to 10 items. |
links[].label required | string | Up to 60 characters. |
links[].url required | string (uri) | Up to 1000 characters. |
show_socials | boolean | The brand's connected profiles as icons Default true. |
hide_badge | boolean | Paid plans only Default false. |
Responses
| Status | Means |
|---|---|
200 | { ok: true, note?, ...the same body as GET } |
400 | code slug_required, slug_length, slug_chars, slug_reserved, bad_url, label_required or too_many_links, with field (e.g. links.2.url) and every problem in errors[] |
409 | code slug_taken |
503 | code bio_unavailable: bio pages are not switched on on this server yet |
curl -X PUT "https://postwire.io/api/bio" \
-H "Authorization: Bearer $POSTWIRE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"brand_id": "b3f1c2d4-8a9e-4f6b-a1c2-3d4e5f6a7b8c",
"slug": "luna-bakery",
"title": "Luna Bakery",
"bio": "Sourdough and custom cakes in Lima. Order by 6 pm for next-day pickup.",
"links": [
{
"label": "Order a cake",
"url": "https://lunabakery.example/cakes"
},
{
"label": "This week'\''s menu",
"url": "https://lunabakery.example/menu"
}
]
}'const res = await fetch("https://postwire.io/api/bio", {
method: "PUT",
headers: { Authorization: `Bearer ${process.env.POSTWIRE_API_KEY}`, "Content-Type": "application/json" },
body: JSON.stringify({
"brand_id": "b3f1c2d4-8a9e-4f6b-a1c2-3d4e5f6a7b8c",
"slug": "luna-bakery",
"title": "Luna Bakery",
"bio": "Sourdough and custom cakes in Lima. Order by 6 pm for next-day pickup.",
"links": [
{
"label": "Order a cake",
"url": "https://lunabakery.example/cakes"
},
{
"label": "This week's menu",
"url": "https://lunabakery.example/menu"
}
]
}),
});
console.log(res.status, await res.json());import os, requests
r = requests.put(
"https://postwire.io/api/bio",
headers={"Authorization": f"Bearer {os.environ['POSTWIRE_API_KEY']}"},
json={
"brand_id": "b3f1c2d4-8a9e-4f6b-a1c2-3d4e5f6a7b8c",
"slug": "luna-bakery",
"title": "Luna Bakery",
"bio": "Sourdough and custom cakes in Lima. Order by 6 pm for next-day pickup.",
"links": [
{
"label": "Order a cake",
"url": "https://lunabakery.example/cakes",
},
{
"label": "This week's menu",
"url": "https://lunabakery.example/menu",
},
],
},
)
print(r.status_code, r.json())Remove a brand's link-in-bio page
/api/bioThe address becomes free for anyone; the page's views and clicks are deleted with it.
Needs an API key: Authorization: Bearer pw_live_….
Parameters
| Field | Type | Description |
|---|---|---|
brand_id | query, string (uuid) |
Responses
| Status | Means |
|---|---|
200 | { ok: true, removed: <slug> } |
404 | code bio_not_found or brand_not_found |
curl -X DELETE "https://postwire.io/api/bio?brand_id=b3f1c2d4-8a9e-4f6b-a1c2-3d4e5f6a7b8c" \
-H "Authorization: Bearer $POSTWIRE_API_KEY"const res = await fetch("https://postwire.io/api/bio?brand_id=b3f1c2d4-8a9e-4f6b-a1c2-3d4e5f6a7b8c", {
method: "DELETE",
headers: { Authorization: `Bearer ${process.env.POSTWIRE_API_KEY}` },
});
console.log(res.status, await res.json());import os, requests
r = requests.delete(
"https://postwire.io/api/bio?brand_id=b3f1c2d4-8a9e-4f6b-a1c2-3d4e5f6a7b8c",
headers={"Authorization": f"Bearer {os.environ['POSTWIRE_API_KEY']}"},
)
print(r.status_code, r.json())