API Documentation
Everything you need to integrate with the Tampa.dev platform.
Profile & Users
Identity
GET /v1/me
Get the authenticated user's basic identity. Scope: read:user.
curl -H "Authorization: Bearer td_pat_abc123..." \
https://api.tampa.dev/v1/me
{
"data": {
"id": "usr_abc123",
"name": "Jane Developer",
"avatarUrl": "https://avatars.githubusercontent.com/u/12345",
"username": "janedev",
"email": "jane@example.com"
}
}
The email field is only included when the token has the user:email scope.
Profile
GET /v1/profile
Get the authenticated user's full profile. Scope: read:user.
curl -H "Authorization: Bearer td_pat_abc123..." \
https://api.tampa.dev/v1/profile
{
"data": {
"id": "usr_abc123",
"name": "Jane Developer",
"username": "janedev",
"avatarUrl": "https://avatars.githubusercontent.com/u/12345",
"heroImageUrl": null,
"themeColor": "#0891B2",
"bio": "Full-stack developer in Tampa",
"location": "Tampa, FL",
"socialLinks": ["https://github.com/janedev", "https://twitter.com/janedev"],
"role": "user",
"profileVisibility": "public",
"showAchievements": true,
"createdAt": "2025-06-15T10:30:00Z",
"email": "jane@example.com"
}
}
PATCH /v1/profile
Update the authenticated user's profile. Scope: user.
curl -X PATCH \
-H "Authorization: Bearer td_pat_abc123..." \
-H "Content-Type: application/json" \
-d '{
"bio": "Building cool stuff in Tampa",
"location": "Tampa, FL",
"themeColor": "#E85A4F"
}' \
https://api.tampa.dev/v1/profile
{
"data": {
"id": "usr_abc123",
"name": "Jane Developer",
"username": "janedev",
"bio": "Building cool stuff in Tampa",
"location": "Tampa, FL",
"themeColor": "#E85A4F"
}
}
Updatable fields:
| Field | Type | Constraints |
|---|---|---|
name | string | 1-100 characters |
username | string | 3-30 chars, alphanumeric + hyphens, lowercased |
avatarUrl | string | null | Valid URL |
heroImageUrl | string | null | Valid URL |
themeColor | string | null | One of: coral, ocean, sunset, forest, violet, rose, slate, sky |
bio | string | null | Max 500 characters |
location | string | null | Max 100 characters |
socialLinks | string[] | null | Up to 5 valid URLs |
showAchievements | boolean | Show/hide achievements on profile |
profileVisibility | string | public or private |
GET /v1/profile/email
Get the authenticated user's email address. Scope: user:email.
curl -H "Authorization: Bearer td_pat_abc123..." \
https://api.tampa.dev/v1/profile/email
{
"data": {
"email": "jane@example.com"
}
}
Entitlements
GET /v1/profile/entitlements
Get the authenticated user's active entitlements. Scope: user.
curl -H "Authorization: Bearer td_pat_abc123..." \
https://api.tampa.dev/v1/profile/entitlements
{
"data": [
{
"entitlement": "group_creation",
"source": "admin_grant",
"grantedAt": "2025-09-01T00:00:00Z",
"expiresAt": null
},
{
"entitlement": "badge_issuer",
"source": "admin_grant",
"grantedAt": "2025-09-01T00:00:00Z",
"expiresAt": "2026-09-01T00:00:00Z"
}
]
}
Entitlements are API-only and never exposed on public profiles.
Portfolio
GET /v1/profile/portfolio
List the authenticated user's portfolio items. Scope: read:portfolio.
curl -H "Authorization: Bearer td_pat_abc123..." \
https://api.tampa.dev/v1/profile/portfolio
{
"data": [
{
"id": "pf_abc123",
"userId": "usr_abc123",
"title": "My Open Source Project",
"description": "A CLI tool for developers",
"url": "https://github.com/janedev/project",
"imageUrl": null,
"sortOrder": 0,
"createdAt": "2025-10-01T12:00:00Z"
}
]
}
POST /v1/profile/portfolio
Create a portfolio item. Scope: write:portfolio.
curl -X POST \
-H "Authorization: Bearer td_pat_abc123..." \
-H "Content-Type: application/json" \
-d '{
"title": "My Project",
"url": "https://example.com",
"description": "A cool project"
}' \
https://api.tampa.dev/v1/profile/portfolio
{
"data": {
"id": "pf_def456",
"userId": "usr_abc123",
"title": "My Project",
"description": "A cool project",
"url": "https://example.com",
"imageUrl": null,
"sortOrder": 0,
"createdAt": "2025-11-15T09:00:00Z"
}
}
PATCH /v1/profile/portfolio/:id
Update a portfolio item. Scope: write:portfolio.
curl -X PATCH \
-H "Authorization: Bearer td_pat_abc123..." \
-H "Content-Type: application/json" \
-d '{"title": "Updated Title", "sortOrder": 1}' \
https://api.tampa.dev/v1/profile/portfolio/pf_def456
DELETE /v1/profile/portfolio/:id
Delete a portfolio item. Scope: write:portfolio. Returns 204 No Content.
curl -X DELETE \
-H "Authorization: Bearer td_pat_abc123..." \
https://api.tampa.dev/v1/profile/portfolio/pf_def456
Achievements
GET /v1/profile/achievements
Get the authenticated user's achievement progress. Scope: read:user.
curl -H "Authorization: Bearer td_pat_abc123..." \
https://api.tampa.dev/v1/profile/achievements
{
"data": [
{
"key": "first_event",
"name": "First Event",
"description": "Attend your first community event",
"icon": "calendar",
"color": "#4CAF50",
"targetValue": 1,
"currentValue": 1,
"completedAt": "2025-08-20T19:00:00Z",
"badgeSlug": "first-event",
"hidden": false
},
{
"key": "social_butterfly",
"name": "Social Butterfly",
"description": "Follow 10 community members",
"icon": "users",
"color": "#2196F3",
"targetValue": 10,
"currentValue": 3,
"completedAt": null,
"badgeSlug": null,
"hidden": false
}
]
}
Badges
GET /v1/profile/badges
Get the authenticated user's earned badges with rarity information. Scope: read:user.
curl -H "Authorization: Bearer td_pat_abc123..." \
https://api.tampa.dev/v1/profile/badges
{
"data": [
{
"name": "Early Adopter",
"slug": "early-adopter",
"description": "Joined the Tampa.dev community early",
"icon": "🚀",
"iconUrl": "https://td-uploads-public.tampa.dev/emoji/1f680.webp",
"color": "#4CAF50",
"points": 100,
"awardedAt": "2025-06-15T10:30:00Z",
"group": null,
"rarity": {
"tier": "legendary",
"percentage": 2.5
}
},
{
"name": "First Event",
"slug": "first-event",
"description": "Attended your first community event",
"icon": "📅",
"iconUrl": "https://td-uploads-public.tampa.dev/emoji/1f4c5.webp",
"color": "#2196F3",
"points": 50,
"awardedAt": "2025-08-20T19:00:00Z",
"group": {
"id": "grp_abc123",
"name": "Tampa.dev",
"urlname": "tampadevs",
"photoUrl": "https://cdn.tampa.dev/groups/tampadevs/logo.png"
},
"rarity": {
"tier": "common",
"percentage": 45.2
}
}
]
}
Rarity tiers:
| Tier | Percentage Held |
|---|---|
legendary | < 5% |
epic | 5-10% |
rare | 10-25% |
uncommon | 25-50% |
common | > 50% |
Rarity is calculated dynamically based on the percentage of all platform users who hold each badge.
Personal Access Tokens
GET /v1/profile/tokens
List the authenticated user's PATs. Scope: user. The token value is never returned -- only the prefix.
curl -H "Authorization: Bearer td_pat_abc123..." \
https://api.tampa.dev/v1/profile/tokens
{
"data": [
{
"id": "tok_abc123",
"name": "CI/CD Pipeline",
"tokenPrefix": "td_pat_a1b2",
"scopes": "read:events,read:groups",
"expiresAt": "2026-06-15T00:00:00Z",
"createdAt": "2025-12-15T10:00:00Z",
"lastUsedAt": "2026-01-30T14:22:00Z"
}
]
}
POST /v1/profile/tokens
Create a new PAT. Scope: user. The full token value is returned only in this response -- store it securely.
curl -X POST \
-H "Authorization: Bearer td_pat_abc123..." \
-H "Content-Type: application/json" \
-d '{
"name": "My Integration",
"scopes": ["read:events", "read:groups"],
"expiresInDays": 90
}' \
https://api.tampa.dev/v1/profile/tokens
{
"data": {
"id": "tok_def456",
"name": "My Integration",
"token": "td_pat_a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2",
"tokenPrefix": "td_pat_a1b2",
"scopes": "read:events,read:groups",
"expiresAt": "2026-04-30T10:00:00Z",
"createdAt": "2026-01-31T10:00:00Z"
}
}
DELETE /v1/profile/tokens/:id
Revoke a PAT. Scope: user. Returns 204 No Content.
curl -X DELETE \
-H "Authorization: Bearer td_pat_abc123..." \
https://api.tampa.dev/v1/profile/tokens/tok_def456
Linked Accounts
GET /v1/me/linked-accounts
List connected OAuth providers. Scope: read:user.
curl -H "Authorization: Bearer td_pat_abc123..." \
https://api.tampa.dev/v1/me/linked-accounts
{
"data": [
{
"provider": "github",
"providerUsername": "janedev",
"providerEmail": "jane@example.com",
"createdAt": "2025-06-15T10:30:00Z"
},
{
"provider": "google",
"providerUsername": null,
"providerEmail": "jane@gmail.com",
"createdAt": "2025-07-01T08:00:00Z"
}
]
}
Following
| Method | Endpoint | Scope | Description |
|---|---|---|---|
POST | /v1/users/:username/follow | user | Follow a user |
DELETE | /v1/users/:username/follow | user | Unfollow a user |
GET | /v1/users/:username/followers | read:user | List a user's followers |
GET | /v1/users/:username/following | read:user | List who a user follows |
POST /v1/users/:username/follow
curl -X POST \
-H "Authorization: Bearer td_pat_abc123..." \
https://api.tampa.dev/v1/users/johndoe/follow
New follow (201 Created):
{
"data": {
"following": true
}
}
Already following (200 OK):
{
"data": {
"alreadyFollowing": true
}
}
GET /v1/users/:username/followers
curl -H "Authorization: Bearer td_pat_abc123..." \
https://api.tampa.dev/v1/users/janedev/followers
{
"data": [
{
"username": "johndoe",
"name": "John Doe",
"avatarUrl": "https://avatars.githubusercontent.com/u/67890",
"followedAt": "2025-12-01T15:00:00Z"
}
],
"pagination": {
"total": 1,
"limit": 20,
"offset": 0,
"hasMore": false
}
}
Uploads
POST /v1/uploads/request
Request a presigned upload URL for direct upload to R2 storage. Scope: user.
curl -X POST \
-H "Authorization: Bearer td_pat_abc123..." \
-H "Content-Type: application/json" \
-d '{
"category": "avatar",
"filename": "avatar.png",
"contentType": "image/png",
"size": 12345
}' \
https://api.tampa.dev/v1/uploads/request
{
"data": {
"uploadUrl": "https://uploads.tampa.dev/...",
"publicUrl": "https://cdn.tampa.dev/avatars/usr_abc123/avatar.png"
}
}
Allowed content types: image/jpeg, image/png, image/webp, image/gif. Maximum file size: 5MB.
Onboarding
| Method | Endpoint | Scope | Description |
|---|---|---|---|
GET | /v1/me/onboarding | user | Get onboarding steps with completion status |
POST | /v1/me/onboarding/:stepKey/dismiss | user | Dismiss an onboarding step |
POST | /v1/me/onboarding/dismiss-all | user | Dismiss all onboarding steps |
Onboarding steps are automatically completed when corresponding domain events fire (e.g., setting your username, joining a group, earning XP).
Public Users
These endpoints do not require authentication.
GET /users
List users with public profiles.
curl "https://api.tampa.dev/users?search=jane&limit=10"
Query parameters:
search-- Filter by name or usernamebadge-- Filter by badge slug (only return users who hold this badge)limit-- Number of results (default 20, max 100)offset-- Pagination offset (default 0)
GET /users/:username
Get a user's public profile. Includes badges, achievements, favorite groups, portfolio items, and XP score.
curl "https://api.tampa.dev/users/janedev"