Profiles & links
The bread-and-butter API surface. Every Linkstacked profile is the top-level container, and every link belongs to exactly one profile.
Create a profile
mutation CreateProfile($input: CreateProfileInput!) {
createProfile(input: $input) {
profile { _id username displayName }
}
}{
"input": {
"username": "your-handle",
"displayName": "Your Name",
"bio": "Optional one-liner shown under the avatar."
}
}Usernames are globally unique and case-insensitive. Reserved keywords
(/api, /dashboard, etc.) are rejected with a structured error so your
client can show an inline message without parsing strings.
Add a link
Most fields on Link are optional — only url and title are required.
mutation CreateLink($input: CreateLinkInput!) {
createLink(input: $input) {
link { _id url title icon position }
}
}Common variants:
- Plain URL —
{ url, title }is the minimum viable link. - Custom icon — pass
iconKey(e.g."spotify") oriconAssetIdfor a user-uploaded image. - Scheduled — pair with the scheduling
API to set a
scheduleConfig.
Reorder
Profiles render links in position order, ascending. Move a link by
calling reorderLinks with the desired ordered list of IDs — Linkstacked
recomputes positions in a single transaction so you don't have to chain
N updates:
mutation Reorder($linkIds: [ID!]!) {
reorderLinks(linkIds: $linkIds) {
profile { _id }
}
}Read a public profile
The same data the public profile page renders is exposed through
publicProfileByUsername:
query Public($username: String!) {
publicProfileByUsername(username: $username) {
profile {
_id displayName bio avatarUrl
appearance { themeId font layout }
}
links { _id url title icon position }
}
}Public reads are unauthenticated — no bearer required — but rate-limited
per IP. If you're building a server-side renderer, send your own
X-Forwarded-For header so the bucket isn't shared with every other
caller from your egress.
Custom domains and QR-coded routes
publicProfileByDomain and publicProfileByQRCodeId mirror the
username route for branded surfaces — see QR &
pixels for the QR side.