Team
The shared workspace that owns tracks, albums, sessions, and chat — plus members, invites, plans, and socials.
A team is the tenancy boundary in Aden. Every resource — tracks, albums, sessions, chat, calendar events, contacts — belongs to exactly one team. Users belong to many teams and switch between them in the app.
If you're integrating against Aden, the team ID is the most important parameter you'll pass.
What a team represents
A team can be a single artist, a band, a label imprint, or a production studio. It carries:
- Members — users with a role on the team.
- Plan — the subscription tier that controls features and rate limits.
- Identity — name, avatar, socials, links shown on the public team page.
- Media — uploads attached to the team itself (press kit, brand assets).
Data model
| Field | Type | Notes |
|---|---|---|
id | number | Stable numeric ID. |
name | string | Display name. |
slug | string | URL-safe handle, used for the public page. |
avatar_url | string | null | Team avatar / logo. |
plan | Plan | free, air, pro, ultra, max. |
created_at | string | ISO 8601. |
updated_at | string | ISO 8601. |
Sub-resources:
- Members — the roster.
- Invites — pending email invites.
- Socials — Spotify, Instagram, TikTok, etc.
- Media — files attached to the team.
- Plan — current subscription state.
Membership and roles
Members live in the user_teams table and carry a role. Roles are coarse —
they gate which actions a user can take inside the team. Granular permissions
(like access to a specific track) layer on top via track-level
collaborators.
Endpoints:
GET /teams/{id}/members— list members and roles.PATCH /teams/{id}/members— change a member's role.DELETE /teams/{id}/members— remove a member.
Invites
Invites are email-addressed and expire. The invitee accepts in the app and becomes a member.
GET /teams/{id}/invites— list pending invites.POST /teams/{id}/invites— send one.DELETE /teams/{id}/invites— revoke.
Plans
A team's plan controls which features are available and the per-action rate limits. The plan hierarchy is:
free < air < pro < ultra < maxRead the current plan via GET /teams/{id}/plan. Plan changes are driven by
Polar webhooks — your integration never writes a plan directly. To gate a
feature in your own UI, check the team plan against
packages/shared/src/plans/feature-plan-requirements.ts.
Socials and links
Socials are surfaced on the team's public page and pulled into the calendar for things like "release day post."
GET /teams/socials— list across the user's teams.POST /teams/socials,PATCH /teams/socials,DELETE /teams/socials.
Media
Team media is for assets attached to the workspace itself rather than a track or album — press shots, EPKs, brand kits.
GET /teams/{id}/mediaPOST /teams/{id}/mediaDELETE /teams/{id}/media/{mediaId}
Auth notes
A few endpoints in this section are session-only — they require a
Supabase user session, not an API key. Anything that mutates membership
(/members, /invites) and /plan is in this group, so a user is always
attached to the action.
API keys can read team data and operate on tracks/albums/sessions. See Authentication for the full split.
Recipes
Bootstrap a new team integration
const { data: team } = await aden.api.v1.teams({ id: teamId }).get()
const { data: members } = await aden.api.v1.teams({ id: teamId }).members.get()
const { data: plan } = await aden.api.v1.teams({ id: teamId }).plan.get()
console.log(`${team.name} (${plan.tier}) — ${members.length} members`)Invite a collaborator
await aden.api.v1.teams({ id: teamId }).invites.post({
email: 'producer@example.com',
role: 'editor',
})Mirror team socials into your CMS
const { data: socials } = await aden.api.v1.teams.socials.get()
for (const social of socials ?? []) {
await cms.upsert('socials', { id: social.id, ...social })
}Related
- Tracks and Albums — what a team owns.
- Authentication — API keys vs. session tokens.
- Rate limits — per-plan ceilings.