← knowledge.oriz.in

GitHub profile customization — what works via API vs manual

runbook githubprofileapipinningmanual

GitHub profile customization — what works via API

TL;DR

Field API path Token scope Notes
bio PATCH /user user Works. Up to 160 chars.
location PATCH /user user Works. Trim trailing spaces or PATCH them off.
name PATCH /user user Works.
company PATCH /user user Works.
blog (website) PATCH /user user Works.
twitter_username PATCH /user user Works (despite the X rebrand the field name stays).
hireable PATCH /user user Works. Boolean.
email PATCH /user user Works (must be a verified email).
Pinned repositories NONE n/a Not exposed by REST or GraphQL. Manual UI only.
Pinned gists NONE n/a Same — manual only.
Profile README Standard repo APIs on <user>/<user> repo Edit the README in <user>/<user> repo.
Avatar POST /user/avatar user Documented 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

Recommended split