platforms/devplace/rest_profiles_and_social_graph.md

DevPlace REST: Profiles and the Social Graph

Profile reads and updates, API-key regeneration, avatar and award rendering, per-user AI correction, modifier, Telegram and notification settings, and the follow, block and mute endpoints with their follower and following listings.

Profile data, the follow graph, the leaderboard, and avatar generation. Find users with Search & Lookups; follows generate entries in Notifications.

Every endpoint follows the shared Conventions & Errors (auth, content negotiation, pagination, status codes); see Authentication for the four ways to sign requests.

GET /profile - View your own profile

Render the signed-in user's own profile, in the exact format of GET /profile/{username}. Requires authentication.

Minimal role: Member

Parameters

NameInTypeRequiredDescription
tabqueryenumnoProfile tab. Allowed: posts, activity, followers, following, media, awards.

GET /profile/{username} - View a profile

Render a user profile, including an online-presence indicator (JSON exposes profileonline, profileuser.lastseen, xpnextlevel, and xpprogress_pct). Returns an HTML page.

Minimal role: Public

Parameters

NameInTypeRequiredDescription
usernamepathstringyesTarget username.
tabqueryenumnoProfile tab. Allowed: posts, activity, followers, following, media, awards.

Level progress: xpnextlevel = level * 100 (total XP needed), xpprogresspct = xp % 100 (percentage towards next level). Both are also embedded in profile_user.

Sample response

{
  "profile_user": {
    "uid": "UID",
    "username": "username",
    "avatar_seed": "string",
    "bio": "text",
    "location": "string",
    "git_link": "string",
    "website": "string",
    "level": 0,
    "xp": 0,
    "xp_progress_pct": 0,
    "xp_next_level": 0,
    "stars": 0,
    "created_at": "2026-01-01T00:00:00+00:00",
    "last_seen": "string"
  },
  "posts": [
    {
      "post": {
        "uid": "UID",
        "slug": "slug",
        "user_uid": "UID",
        "title": "Title",
        "content": "text",
        "topic": "random",
        "stars": 0,
        "image": "string",
        "project_uid": "UID",
        "created_at": "2026-01-01T00:00:00+00:00",
        "updated_at": "2026-01-01T00:00:00+00:00"
      },
      "maturity": "string",
      "author": {
        "uid": "UID",
        "username": "username",
        "avatar_seed": "string",
        "bio": "text",
        "location": "string",
        "git_link": "string",
        "website": "string",
        "level": 0,
        "xp": 0,
        "xp_progress_pct": 0,
        "xp_next_level": 0,
        "stars": 0,
        "created_at": "2026-01-01T00:00:00+00:00",
        "last_seen": "string"
      },
      "time_ago": "2 hours ago",
      "my_vote": 0,
      "comment_count": 0,
      "attachments": [
        {
          "uid": "UID",
          "filename": "string",
          "url": "/path",
          "size": 0,
          "is_image": false,
          "is_video": false,
          "mime_type": "string",
          "created_at": "2026-01-01T00:00:00+00:00",
          "can_modify": false
        }
      ],
      "recent_comments": [
        {
          "comment": {
            "uid": "UID",
            "user_uid": "UID",
            "content": "text",
            "parent_uid": "UID",
            "target_type": "string",
            "target_uid": "UID",
            "created_at": "2026-01-01T00:00:00+00:00"
          },
          "author": {
            "uid": "UID",
            "username": "username",
            "avatar_seed": "string",
            "bio": "text",
            "location": "string",
            "git_link": "string",
            "website": "string",
            "level": 0,
            "xp": 0,
            "xp_progress_pct": 0,
            "xp_next_level": 0,
            "stars": 0,
            "created_at": "2026-01-01T00:00:00+00:00",
            "last_seen": "string"
          },
          "time_ago": "2 hours ago",
          "votes": {
            "up": 0,
            "down": 0
          },
          "my_vote": 0,
          "children": [],
          "attachments": [
            {
              "uid": "UID",
              "filename": "string",
              "url": "/path",
              "size": 0,
              "is_image": false,
              "is_video": false,
              "mime_type": "string",
              "created_at": "2026-01-01T00:00:00+00:00",
              "can_modify": false
            }
          ],
          "reactions": {
            "counts": {},
            "mine": []
          }
        }
      ],
      "reactions": {
        "counts": {},
        "mine": []
      },
      "bookmarked": false,
      "poll": {
        "uid": "UID",
        "question": "string",
        "options": [
          {
            "uid": "UID",
            "label": "string",
            "count": 0,
            "votes": 0,
            "pct": 0
          }
        ],
        "total": 0,
        "my_choice": "string",
        "voted": "string"
      },
      "project_link": {
        "uid": "UID",
        "name": "string",
        "slug": "slug",
        "url": "/path"
      }
    }
  ],
  "badges": [
    {
      "name": "string",
      "icon": "string",
      "description": "text",
      "created_at": "2026-01-01T00:00:00+00:00"
    }
  ],
  "achievements": [
    {}
  ],
  "badge_total": 0,
  "badge_earned": 0,
  "projects": [
    {
      "uid": "UID",
      "slug": "slug",
      "user_uid": "UID",
      "title": "Title",
      "description": "text",
      "project_type": "string",
      "status": "published",
      "platforms": null,
      "stars": 0,
      "is_private": false,
      "read_only": false,
      "release_date": "string",
      "demo_date": "string",
      "created_at": "2026-01-01T00:00:00+00:00",
      "updated_at": "2026-01-01T00:00:00+00:00"
    }
  ],
  "gists": [
    {
      "gist": {
        "uid": "UID",
        "slug": "slug",
        "user_uid": "UID",
        "title": "Title",
        "description": "text",
        "source_code": "string",
        "language": "python",
        "stars": 0,
        "created_at": "2026-01-01T00:00:00+00:00",
        "updated_at": "2026-01-01T00:00:00+00:00"
      },
      "maturity": "string",
      "author": {
        "uid": "UID",
        "username": "username",
        "avatar_seed": "string",
        "bio": "text",
        "location": "string",
        "git_link": "string",
        "website": "string",
        "level": 0,
        "xp": 0,
        "xp_progress_pct": 0,
        "xp_next_level": 0,
        "stars": 0,
        "created_at": "2026-01-01T00:00:00+00:00",
        "last_seen": "string"
      },
      "time_ago": "2 hours ago",
      "my_vote": 0,
      "comment_count": 0,
      "recent_comments": [
        {
          "comment": {
            "uid": "UID",
            "user_uid": "UID",
            "content": "text",
            "parent_uid": "UID",
            "target_type": "string",
            "target_uid": "UID",
            "created_at": "2026-01-01T00:00:00+00:00"
          },
          "author": {
            "uid": "UID",
            "username": "username",
            "avatar_seed": "string",
            "bio": "text",
            "location": "string",
            "git_link": "string",
            "website": "string",
            "level": 0,
            "xp": 0,
            "xp_progress_pct": 0,
            "xp_next_level": 0,
            "stars": 0,
            "created_at": "2026-01-01T00:00:00+00:00",
            "last_seen": "string"
          },
          "time_ago": "2 hours ago",
          "votes": {
            "up": 0,
            "down": 0
          },
          "my_vote": 0,
          "children": [],
          "attachments": [
            {
              "uid": "UID",
              "filename": "string",
              "url": "/path",
              "size": 0,
              "is_image": false,
              "is_video": false,
              "mime_type": "string",
              "created_at": "2026-01-01T00:00:00+00:00",
              "can_modify": false
            }
          ],
          "reactions": {
            "counts": {},
            "mine": []
          }
        }
      ]
    }
  ],
  "current_tab": "string",
  "posts_count": 0,
  "is_following": false,
  "is_blocked": false,
  "is_muted": false,
  "is_owner": false,
  "profile_online": false,
  "can_view_api_key": false,
  "api_key": "string",
  "ai_correction_enabled": false,
  "ai_correction_sync": false,
  "ai_correction_prompt": "string",
  "ai_modifier_enabled": false,
  "ai_modifier_sync": false,
  "ai_modifier_prompt": "string",
  "interactions_enabled": false,
  "interactions_source": "string",
  "interactions_default": false,
  "interactions_override": false,
  "telegram_paired": false,
  "notif_telegram_paired": false,
  "can_manage_customization": false,
  "cust_disable_global": false,
  "cust_disable_pagetype": false,
  "ai_quota": {},
  "correction_usage": {},
  "modifier_usage": {},
  "activities": [
    null
  ],
  "rank": 0,
  "heatmap": null,
  "heatmap_months": null,
  "streak": null,
  "people": [
    null
  ],
  "follow_pagination": null,
  "followers_count": 0,
  "following_count": 0,
  "viewer_is_admin": false,
  "xp_next_level": 0,
  "xp_progress_pct": 0,
  "media": [
    {
      "uid": "UID",
      "original_filename": "string",
      "file_size": 0,
      "mime_type": "string",
      "url": "/path",
      "thumbnail_url": "/path",
      "has_thumbnail": false,
      "is_image": false,
      "is_video": false,
      "target_type": "string",
      "target_uid": "UID",
      "target_url": "/path",
      "created_at": "2026-01-01T00:00:00+00:00"
    }
  ],
  "media_pagination": null,
  "notification_prefs": [
    null
  ],
  "awards": [
    {
      "uid": "UID",
      "slug": "slug",
      "description": "text",
      "giver_uid": "UID",
      "receiver_uid": "UID",
      "generated_at": "string",
      "created_at": "2026-01-01T00:00:00+00:00",
      "image_url": "/path",
      "thumb_url": "/path",
      "giver": {
        "uid": "UID",
        "username": "username",
        "avatar_seed": "string",
        "bio": "text",
        "location": "string",
        "git_link": "string",
        "website": "string",
        "level": 0,
        "xp": 0,
        "xp_progress_pct": 0,
        "xp_next_level": 0,
        "stars": 0,
        "created_at": "2026-01-01T00:00:00+00:00",
        "last_seen": "string"
      }
    }
  ],
  "awards_pagination": null,
  "awards_count": 0,
  "prominent_award": {
    "uid": "UID",
    "slug": "slug",
    "description": "text",
    "giver_uid": "UID",
    "receiver_uid": "UID",
    "generated_at": "string",
    "created_at": "2026-01-01T00:00:00+00:00",
    "image_url": "/path",
    "thumb_url": "/path",
    "giver": {
      "uid": "UID",
      "username": "username",
      "avatar_seed": "string",
      "bio": "text",
      "location": "string",
      "git_link": "string",
      "website": "string",
      "level": 0,
      "xp": 0,
      "xp_progress_pct": 0,
      "xp_next_level": 0,
      "stars": 0,
      "created_at": "2026-01-01T00:00:00+00:00",
      "last_seen": "string"
    }
  },
  "can_give_award": false,
  "consents": [
    null
  ],
  "mature_opt_in": false,
  "age_band": "string",
  "terms_version": "string",
  "terms_accepted_at": "string",
  "current_terms_version": "string",
  "suspended_until": "string",
  "suspension_reason": "string",
  "deletion_grace_hours": 0
}

POST /profile/update - Update your profile

Update your own bio and links.

Minimal role: Member

Parameters

NameInTypeRequiredDescription
bioformtextareanoBio, up to 500 characters.
locationformstringnoLocation, up to 200 characters.
git_linkformstringnoGit profile URL.
websiteformstringnoPersonal website URL.

Sample response

{
  "ok": true,
  "redirect": "/profile/YOUR_USERNAME",
  "data": null
}

POST /profile/{username}/ai-correction - Configure AI content correction

Enable or disable automatic AI rewriting of your prose and set the correction instruction. Opt-in, default off. Admins may target any user.

Minimal role: Member

Parameters

NameInTypeRequiredDescription
usernamepathstringyesProfile owner. Must be yourself unless you are an admin.
enabledformbooleannotrue to enable background AI correction, false to disable it.
syncformbooleannotrue to apply the correction synchronously (the save waits), false for background.
promptformtextareanoCorrection instruction, up to 20000 characters.

Sample response

{
  "ok": true,
  "redirect": "/profile/bob_test",
  "data": {
    "url": "/profile/bob_test",
    "enabled": true,
    "sync": false,
    "prompt": "Leave literary as is, only do punctuation and casing"
  }
}

POST /profile/{username}/interactions - Configure Devii interactive widgets

Enable or disable CA-IWP interactive prompts (ui_prompt) for this account, or reset to the administrator default. Guests always use the site default. Admins may target any user.

Minimal role: Member

Parameters

NameInTypeRequiredDescription
usernamepathstringyesProfile owner. Must be yourself unless you are an admin.
enabledformbooleannotrue to enable interactive widgets, false to disable. Ignored when reset is true.
resetformbooleannotrue to clear the user override and inherit the administrator default.

Sample response

{
  "ok": true,
  "redirect": "/profile/bob_test",
  "data": {
    "url": "/profile/bob_test",
    "enabled": true,
    "source": "user",
    "default": true,
    "override": true
  }
}

POST /profile/{username}/ai-modifier - Configure the AI modifier

Enable or disable the inline '@ai <instruction>' modifier on your prose and set its prompt. Enabled by default, applied synchronously by default. Admins may target any user.

Minimal role: Member

Parameters

NameInTypeRequiredDescription
usernamepathstringyesProfile owner. Must be yourself unless you are an admin.
enabledformbooleannotrue to enable the AI modifier, false to disable it.
syncformbooleannotrue to apply the modification synchronously (the save waits), false for background.
promptformtextareanoModifier instruction, up to 20000 characters.

Sample response

{
  "ok": true,
  "redirect": "/profile/bob_test",
  "data": {
    "url": "/profile/bob_test",
    "enabled": true,
    "sync": true,
    "prompt": "Execute what is behind `@ai` (the prompt) and replace that part including `@ai`"
  }
}

POST /profile/{username}/telegram - Pair or unpair Telegram

Request a single-use Telegram pairing code, or unpair the connected account. Send action=request (default) to receive a code valid for a few minutes, or action=unpair to disconnect. Admins may target any user.

Minimal role: Member

Parameters

NameInTypeRequiredDescription
usernamepathstringyesProfile owner. Must be yourself unless you are an admin.
actionformstringnoEither request to issue a pairing code, or unpair to disconnect Telegram.

Sample response

{
  "ok": true,
  "paired": false,
  "code": "1234",
  "expires_at": "2026-06-18T12:05:00+00:00",
  "ttl_minutes": 5
}

POST /profile/regenerate-api-key - Regenerate your API key

Issue a new API key and invalidate the current one.

Minimal role: Member

> Running this invalidates the key these documentation panels use. Do it from your profile page instead, then reload these docs.

Sample response

{
  "api_key": "NEW_UUID"
}

POST /profile/{username}/award - Give a member an award

Create a pending award on another member's profile and enqueue image generation.

Minimal role: Member

Parameters

NameInTypeRequiredDescription
usernamepathstringyesReceiver username.
descriptionjsonstringyesAward message (1-125 characters).

Sample response

{
  "ok": true,
  "data": {
    "award_uid": "AWARD_UID",
    "award_slug": "abc123-great-work"
  }
}

POST /profile/{username}/regenerate-avatar - Regenerate a user avatar

Replace the user's avatar with a freshly generated random one.

Minimal role: Member

Parameters

NameInTypeRequiredDescription
usernamepathstringyesProfile owner. Allowed for the owner or any admin.

> Irreversible: the previous avatar is gone for good and cannot be brought back.

Sample response

{
  "ok": true,
  "data": {
    "url": "/profile/retoor",
    "avatar_seed": "NEW_UUID",
    "avatar_url": "/avatar/multiavatar/NEW_UUID?size=80"
  }
}

POST /profile/{username}/customization/global - Toggle site-wide customizations

Show or suppress your site-wide custom CSS and JS without deleting it. Admins may target any user.

Minimal role: Member

Parameters

NameInTypeRequiredDescription
usernamepathstringyesProfile owner. Must be yourself unless you are an admin.
valueformbooleanno1 to show your site-wide customizations, 0 to suppress them.

Sample response

{
  "ok": true,
  "redirect": "/profile/YOUR_USERNAME",
  "data": {
    "url": "/profile/YOUR_USERNAME",
    "cust_disable_global": true
  }
}

POST /profile/{username}/customization/pagetype - Toggle per-page customizations

Show or suppress your per-page custom CSS and JS without deleting it. Admins may target any user.

Minimal role: Member

Parameters

NameInTypeRequiredDescription
usernamepathstringyesProfile owner. Must be yourself unless you are an admin.
valueformbooleanno1 to show your per-page customizations, 0 to suppress them.

Sample response

{
  "ok": true,
  "redirect": "/profile/YOUR_USERNAME",
  "data": {
    "url": "/profile/YOUR_USERNAME",
    "cust_disable_pagetype": true
  }
}

POST /profile/{username}/notifications - Toggle a notification preference

Enable or disable one notification type on one channel (in-app or push). Admins may target any user. Types: comment, reply, mention, vote, follow, message, badge, level, issue, reminder, harvest_stolen.

Minimal role: Member

Parameters

NameInTypeRequiredDescription
usernamepathstringyesProfile owner. Must be yourself unless you are an admin.
notification_typeformstringyesOne of: comment, reply, mention, vote, follow, message, badge, level, issue, reminder, harvest_stolen.
channelformstringyesOne of in_app, push or telegram (telegram is off by default and requires a paired Telegram account).
valueformbooleanno1 to deliver this notification on this channel, 0 to suppress it.

Sample response

{
  "ok": true,
  "redirect": "/profile/retoor?tab=notifications",
  "data": {
    "notification_type": "vote",
    "channel": "push",
    "value": false
  }
}

POST /profile/{username}/notifications/reset - Reset notification preferences

Clear all of a user's notification overrides so every type falls back to the platform default. Admins may target any user.

Minimal role: Member

Parameters

NameInTypeRequiredDescription
usernamepathstringyesProfile owner. Must be yourself unless you are an admin.

Sample response

{
  "ok": true,
  "redirect": "/profile/retoor?tab=notifications"
}

POST /media/{uid}/delete - Delete media

Remove one of your uploaded media attachments. It disappears from your profile Media tab and from any post, project, gist, or other place it was attached. You can delete media you uploaded; administrators may remove any user's media.

Minimal role: Member

Parameters

NameInTypeRequiredDescription
uidpathstringyesAttachment uid, taken from the Media tab response.

Sample response

{
  "ok": true,
  "redirect": "/profile/retoor?tab=media"
}

POST /follow/{username} - Follow a user

Follow another user. Idempotent.

Minimal role: Member

Parameters

NameInTypeRequiredDescription
usernamepathstringyesUsername to follow.

Sample response

{
  "ok": true,
  "redirect": "/profile/bob_test",
  "data": null
}

POST /follow/unfollow/{username} - Unfollow a user

Stop following a user.

Minimal role: Member

Parameters

NameInTypeRequiredDescription
usernamepathstringyesUsername to unfollow.

Sample response

{
  "ok": true,
  "redirect": "/profile/bob_test",
  "data": null
}

POST /block/{username} - Block a user

Block a user. Their posts, comments and messages are hidden from you everywhere except their own profile, and they can no longer create notifications for you. Idempotent.

Minimal role: Member

Parameters

NameInTypeRequiredDescription
usernamepathstringyesUsername to block.

Sample response

{
  "ok": true,
  "redirect": "/profile/bob_test"
}

POST /block/unblock/{username} - Unblock a user

Reverse a block. Their content becomes visible again.

Minimal role: Member

Parameters

NameInTypeRequiredDescription
usernamepathstringyesUsername to unblock.

Sample response

{
  "ok": true,
  "redirect": "/profile/bob_test"
}

POST /mute/{username} - Mute a user

Mute a user so they can no longer create notifications for you. Their content stays visible. Idempotent.

Minimal role: Member

Parameters

NameInTypeRequiredDescription
usernamepathstringyesUsername to mute.

Sample response

{
  "ok": true,
  "redirect": "/profile/bob_test"
}

POST /mute/unmute/{username} - Unmute a user

Reverse a mute. They can create notifications for you again.

Minimal role: Member

Parameters

NameInTypeRequiredDescription
usernamepathstringyesUsername to unmute.

Sample response

{
  "ok": true,
  "redirect": "/profile/bob_test"
}

GET /profile/{username}/followers - List followers

List the users who follow a profile, 25 per page. Returns JSON.

Minimal role: Public

Parameters

NameInTypeRequiredDescription
usernamepathstringyesTarget username.
pagequeryintegernoPage number, 25 per page.

Sample response

{
  "username": "retoor",
  "mode": "followers",
  "count": 2,
  "page": 1,
  "total_pages": 1,
  "followers": [
    {
      "uid": "UUID",
      "username": "bob_test",
      "bio": "Building things.",
      "is_following": false
    }
  ]
}

GET /profile/{username}/following - List following

List the users a profile follows, 25 per page. Returns JSON.

Minimal role: Public

Parameters

NameInTypeRequiredDescription
usernamepathstringyesTarget username.
pagequeryintegernoPage number, 25 per page.

Sample response

{
  "username": "retoor",
  "mode": "following",
  "count": 1,
  "page": 1,
  "total_pages": 1,
  "following": [
    {
      "uid": "UUID",
      "username": "alice_test",
      "bio": "",
      "is_following": true
    }
  ]
}

GET /leaderboard - View the leaderboard

Top contributors by stars. Returns an HTML page.

Minimal role: Public

Sample response

{
  "entries": [
    {
      "uid": "UID",
      "username": "username",
      "avatar_seed": "string",
      "stars": 0,
      "level": 0,
      "rank": 0
    }
  ],
  "user_rank": 0,
  "total_members": 0,
  "posts_today": 0,
  "total_projects": 0,
  "total_gists": 0,
  "top_authors": [
    {
      "uid": "UID",
      "username": "username",
      "avatar_seed": "string",
      "bio": "text",
      "location": "string",
      "git_link": "string",
      "website": "string",
      "level": 0,
      "xp": 0,
      "xp_progress_pct": 0,
      "xp_next_level": 0,
      "stars": 0,
      "created_at": "2026-01-01T00:00:00+00:00",
      "last_seen": "string"
    }
  ],
  "featured_news": [
    {
      "uid": "UID",
      "slug": "slug",
      "title": "Title",
      "description": "text",
      "content": "text",
      "url": "/path",
      "source_name": "string",
      "author": "string",
      "grade": 0,
      "ai_grade": 0,
      "status": "published",
      "image_url": "/path",
      "featured": 0,
      "has_unique_image": 0,
      "article_published": "string",
      "created_at": "2026-01-01T00:00:00+00:00",
      "synced_at": "2026-01-01T00:00:00+00:00"
    }
  ]
}

GET /awards/{slugoruid}/{size} - Award image redirect

Redirect to the stored PNG attachment for a published award.

Minimal role: Public

Parameters

NameInTypeRequiredDescription
slugoruidpathstringyesAward slug or bare uid.
sizepathenumyesImage size. Allowed: 512, 256, 64.

> Pending or revoked awards return 404.

> Response includes long-lived cache headers.

GET /avatar/{style}/{seed} - Generate an avatar

Deterministic SVG avatar for a seed. Returns an image.

Minimal role: Public

Parameters

NameInTypeRequiredDescription
stylepathenumyesAvatar style. Allowed: multiavatar.
seedpathstringyesSeed string, usually a username.
sizequeryintnoPixel size.