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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
tab | query | enum | no | Profile 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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
username | path | string | yes | Target username. |
tab | query | enum | no | Profile 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 inprofile_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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
bio | form | textarea | no | Bio, up to 500 characters. |
location | form | string | no | Location, up to 200 characters. |
git_link | form | string | no | Git profile URL. |
website | form | string | no | Personal 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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
username | path | string | yes | Profile owner. Must be yourself unless you are an admin. |
enabled | form | boolean | no | true to enable background AI correction, false to disable it. |
sync | form | boolean | no | true to apply the correction synchronously (the save waits), false for background. |
prompt | form | textarea | no | Correction 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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
username | path | string | yes | Profile owner. Must be yourself unless you are an admin. |
enabled | form | boolean | no | true to enable interactive widgets, false to disable. Ignored when reset is true. |
reset | form | boolean | no | true 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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
username | path | string | yes | Profile owner. Must be yourself unless you are an admin. |
enabled | form | boolean | no | true to enable the AI modifier, false to disable it. |
sync | form | boolean | no | true to apply the modification synchronously (the save waits), false for background. |
prompt | form | textarea | no | Modifier 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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
username | path | string | yes | Profile owner. Must be yourself unless you are an admin. |
action | form | string | no | Either 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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
username | path | string | yes | Receiver username. |
description | json | string | yes | Award 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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
username | path | string | yes | Profile 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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
username | path | string | yes | Profile owner. Must be yourself unless you are an admin. |
value | form | boolean | no | 1 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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
username | path | string | yes | Profile owner. Must be yourself unless you are an admin. |
value | form | boolean | no | 1 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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
username | path | string | yes | Profile owner. Must be yourself unless you are an admin. |
notification_type | form | string | yes | One of: comment, reply, mention, vote, follow, message, badge, level, issue, reminder, harvest_stolen. |
channel | form | string | yes | One of in_app, push or telegram (telegram is off by default and requires a paired Telegram account). |
value | form | boolean | no | 1 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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
username | path | string | yes | Profile 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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
uid | path | string | yes | Attachment 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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
username | path | string | yes | Username 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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
username | path | string | yes | Username 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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
username | path | string | yes | Username 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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
username | path | string | yes | Username 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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
username | path | string | yes | Username 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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
username | path | string | yes | Username 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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
username | path | string | yes | Target username. |
page | query | integer | no | Page 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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
username | path | string | yes | Target username. |
page | query | integer | no | Page 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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
slugoruid | path | string | yes | Award slug or bare uid. |
size | path | enum | yes | Image 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
| Name | In | Type | Required | Description |
|---|---|---|---|---|
style | path | enum | yes | Avatar style. Allowed: multiavatar. |
seed | path | string | yes | Seed string, usually a username. |
size | query | int | no | Pixel size. |