type: runbook
status: active
timestamp: 2026-06-26
tags: [github, profile, api, pinning, manual]

GitHub profile customization — what works via API vs manual

GH profile: API-patchable fields vs pinned repos

GitHub profile customization — what works via API

TL;DR

FieldAPI pathToken scopeNotes
bioPATCH /useruserWorks. Up to 160 chars.
locationPATCH /useruserWorks. Trim trailing spaces or PATCH them off.
namePATCH /useruserWorks.
companyPATCH /useruserWorks.
blog (website)PATCH /useruserWorks.
twitter_usernamePATCH /useruserWorks (despite the X rebrand the field name stays).
hireablePATCH /useruserWorks. Boolean.
emailPATCH /useruserWorks (must be a verified email).
Pinned repositoriesNONEn/aNot exposed by REST or GraphQL. Manual UI only.
Pinned gistsNONEn/aSame — manual only.
Profile READMEStandard repo APIs on <user>/<user>repoEdit the README in <user>/<user> repo.
AvatarPOST /user/avataruserDocumented but rate-limited.

Working PATCH example

val="$GH_ADMIN_PAT"
cat > /tmp/patch.json <<'EOF'
{
  "bio": "Software Engineering Specialist at TCS · building free public tools at @chirag127 · React Native + Astro + AI agents",
  "location": "India"
}
EOF
curl -X PATCH \
  -H "Authorization: Bearer $val" \
  -H "Accept: application/vnd.github+json" \
  -H "X-GitHub-Api-Version: 2022-11-28" \
  https://api.github.com/user \
  --data-binary @/tmp/patch.json

Quoting note: any non-ASCII characters (middle dot ·, em dash , …) need a file-based payload + --data-binary. Inline -d strings with shell-quoting break on Windows Git Bash.

Why pinning doesn’t work via API

Investigated 2026-06-26 with full admin PAT (all scopes including user, repo, admin:org):

Why GitHub keeps it manual: profile shape is meant to be a deliberate human action with the actual web UI as the only surface. Automating it would let token leakers reshape victim profiles silently — same threat model as profile-photo changes.

Manual pin flow (~30 seconds)

  1. Go to https://github.com/<your-username> while signed in as yourself.
  2. Click “Customize your pins” (top-right of the Pinned repositories section).
  3. In the modal: uncheck currently-pinned items, check the desired 6 in order.
  4. Click Save pins.

Verification after manual pin

gh api graphql -f query='{
  user(login: "chirag127") {
    pinnedItems(first: 6, types: REPOSITORY) {
      nodes { ... on Repository { nameWithOwner } }
    }
  }
}' --jq '.data.user.pinnedItems.nodes[].nameWithOwner'

Expected output: the 6 repo slugs in the order you checked them.

Anti-patterns tried + failed


Edit on GitHub · Back to index