> ## Documentation Index
> Fetch the complete documentation index at: https://docs.member.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Your account and team

> Find your way around the Account area of the Membership.io admin, and edit your profile, rename or switch teams, and change your password with the matching API requests.

The **Account** page in the admin at [app.member.dev](https://app.member.dev) holds your sign-in details, the team you are working in, its Stripe connection, and its developer tools. Select **Account** in the sidebar to open the account menu, then select **Account settings**. The area has five sections; see [The Account area](#the-account-area).

The [Account area](#the-account-area) below walks through each section of the admin. The sections after it show the API request behind the profile, team, password, and team-switching actions.

A few terms first:

* A **team** is the workspace that owns your hubs, media, and API keys. Signing up creates one for you, and you can belong to more than one. See [Tenancy](/concepts/tenancy).
* The **team owner** is the user who created the team. Only the owner can rename it.
* The **active team** is the team the admin is working in right now. Every admin page shows the active team's data.

To follow the API steps, set the base URL and a platform access token. Get the token by signing in, as shown in [Sign in as a creator](/guides/platform-login). The profile and team-switching requests on this page need a signed-in user's token: a team API key gets `403`. See [Authentication](/concepts/authentication).

```bash theme={null}
export MIO_BASE_URL="https://api.member.dev"
export MIO_ACCESS_TOKEN="<platform access token>"
```

Then look up your user id:

```bash theme={null}
export USER_ID=$(
  curl -s "$MIO_BASE_URL/api/v1/auth/me" \
    -H "Authorization: Bearer $MIO_ACCESS_TOKEN" \
    -H "Accept: application/vnd.api+json" | jq -r '.data.id'
)
```

## The Account area

The Account area splits your settings into five sections. They are listed in a panel on the left of the page, under "Team, payment accounts, developer tools" (stacked above the content on a phone). The page opens on **Profile & security**.

| Section | What it holds |
| - | - |
| **Team** | The team's people and the team's settings. |
| **Profile & security** | Your name, your email (read only), and **Change password**. |
| **Payment accounts** | The team's Stripe connection. |
| **Developer tools** | API keys, webhook endpoints, external login, verified domains, and OAuth clients. |
| **Billing** | A placeholder: "Billing isn't in the API yet". |

### Team

The **Team** section ("People who run the account. Not hub members.") has two tabs, **People** and **Team settings**. Only the team owner can open it. Anyone else sees "Only the team owner can see team members."

**People** lists the team's people, read only:

* Your own row shows your name and email, marked **You**, with your role (**Owner** or **Member**). Select it to open the role and the **Joined** date.
* Other members are not named yet, because the admin cannot read other people's profiles. They are counted in one row, for example "2 other members", with "Names appear once available."
* You cannot invite people, change roles, or remove members here. See [Not yet](#not-yet) for adding a member with the API.

**Team settings** has the **Team name** field, with **Save** (the owner renames the team here), and a **Slug** row: "Set when the team is created; it cannot be changed." If you belong to more than one team, a **Switch team** row opens the account menu.

If you have no active team, the section shows **No active team** and tells you to choose one from the account menu by selecting your avatar in the navigation.

### Profile & security

**Profile & security** ("Your own sign-in") has a **Profile** group with **First name**, **Last name**, and a read-only **Email** ("Contact support to change"). When you change a name, **Save** and **Discard** appear.

The **Security** group has a **Password** row, "Change the password you sign in with.", with a **Change** button. It opens a **Change password** dialog with **Current password**, **New password** (at least 8 characters) and **New password again**, and a **Reset via email instead** link. On success the admin shows "Password changed" and signs your other sessions out. See [Change your password with the API](#change-your-password-with-the-api).

### Payment accounts

**In the admin:** **Payment accounts** ("The Stripe account every hub pays into") connects the team's Stripe account so its hubs can accept payments. The connection belongs to the team and is shared by all of its hubs. Only the team owner can manage it. Anyone else sees "Only the team owner can manage payment accounts."

The section shows one of three states:

| State | What you see | What to do |
| - | - | - |
| Not connected | **Connect Stripe**: "Connect a Stripe account to accept payments for this team's hubs." | Select **Connect Stripe**. |
| Not fully enabled | **Payments aren't enabled**: "Stripe hasn't enabled payments for this team. Check the account status in Stripe." | Select **Continue in Stripe** to finish setup. |
| Connected | **Ready to accept payments**: "This team's Stripe account can accept payments." | Nothing to do. |

The connect buttons take you to Stripe, where you finish onboarding, and then bring you back to this section. The admin checks the status when you return ("Checking payment status…") and shows "Payments are ready." once Stripe has enabled payments. If Stripe cannot be opened, the section says "We couldn't open Stripe. Try again."

Connecting starts from one of the team's hubs. If the team has no hub yet, the **Connect Stripe** button is hidden and the section shows **Create a hub first**: "Connecting Stripe starts from one of this team's hubs." with a **Go to your hubs** link. Create a hub, then come back.

### Developer tools

**Developer tools** ("API keys, webhook endpoints, external login, verified domains, OAuth clients") is for the team owner. Anyone else sees the owner notice and none of the tools below.

* **API keys** are the first group. **Create key** is in the page header. Creating, copying, changing, and revoking keys works as described in [Manage API keys in the admin](/guides/platform-api-keys).
* **Webhooks** lists the team's endpoints by host, with a **Disabled** badge where one is off. **Add endpoint** asks for a name, an endpoint URL, and the hub whose events it receives, then shows the signing secret once. Each row's menu has **Delete**. With no hub yet, the group says "Create a hub first, then send its events to another app."
* Under **Advanced**:
  * **External login** ("Sign in with Google, Facebook or a company login.") lists providers, each with an on/off switch and an **Edit** or **Remove** menu, and **Add provider**. See [Configure an external-login provider](/guides/external-login-admin).
  * **Verified domains** ("Email domains that use the company login.") lists domains. For one still waiting on DNS, it shows the TXT record to add, a copy button, and **Verify now**. **Add domain** asks for a domain and a hub. See [Verified-Domain SSO](/guides/external-login-verified-domains).
  * **OAuth clients** ("Let other apps sign people in with Mio.") lists clients with a copy button for the client ID, a **Delete** menu, and **New client**.

### Billing

**Billing** ("Your Membership.io plan. Hub revenue is under each hub's Payments.") shows "Billing isn't in the API yet": the plan, seats, invoices and payment method are not available in the admin, and today they live with the billing provider.

## Edit your profile with the API

In the admin, this is **Profile & security**, where you edit **First name** and **Last name** and select **Save**. The email is read only ("Contact support to change"); see [The Account area](#the-account-area).

Send the fields you want to change to your own user. The body is flat, with the fields at the top level:

```bash theme={null}
curl -s -X PATCH "$MIO_BASE_URL/api/v1/users/$USER_ID" \
  -H "Authorization: Bearer $MIO_ACCESS_TOKEN" \
  -H "Content-Type: application/vnd.api+json" \
  -H "Accept: application/vnd.api+json" \
  -d '{
    "first_name": "Sam",
    "last_name": "Rivera"
  }' | jq '.data.attributes | {first_name, last_name, email}'
```

Success is `200` with the updated user. Things to know:

* You can only update yourself. Any other user id returns `404`. There is no `PATCH /api/v1/users/me` shortcut, so use your id from `GET /api/v1/auth/me`.
* Send only the fields you want to change. A field you leave out keeps its value. `null` clears that name, and the response is `200` with the name set to `null`. An empty string (`""`) sets the name to an empty string.
* There is no field for your email address, so the API cannot change it either.

<Warning>
  Do not wrap this body in a JSON:API `data` envelope. The endpoint ignores keys it does not recognize, so an enveloped body returns `200` and changes nothing.
</Warning>

Reference: [Update User](/api-reference/users/update-user) · [Get Me](/api-reference/auth/get-me)

## Rename a team with the API

In the admin, the owner renames the team on the **Team settings** tab of **Team**, with **Team name** and **Save**; see [Team](#team). Other members do not see the section: they get "Only the team owner can see team members."

Find the team's id and check whether you own it. A team's `owner_id` is the id of its owner:

```bash theme={null}
curl -s "$MIO_BASE_URL/api/v1/teams" \
  -H "Authorization: Bearer $MIO_ACCESS_TOKEN" \
  -H "Accept: application/vnd.api+json" \
  | jq -r --arg me "$USER_ID" '.data[] | "\(.id)  \(.attributes.name)  owner: \(.attributes.owner_id == $me)"'
```

```bash theme={null}
export TEAM_ID="<team id from the list>"
```

Then rename it. This endpoint accepts a JSON:API envelope or a flat `{"name": "..."}` body:

```bash theme={null}
curl -s -X PATCH "$MIO_BASE_URL/api/v1/teams/$TEAM_ID" \
  -H "Authorization: Bearer $MIO_ACCESS_TOKEN" \
  -H "Content-Type: application/vnd.api+json" \
  -H "Accept: application/vnd.api+json" \
  -d '{
    "data": {
      "type": "teams",
      "attributes": {
        "name": "Member Academy Team"
      }
    }
  }' | jq '.data | {id, name: .attributes.name, slug: .attributes.slug}'
```

Success is `200` with the updated team. Only the team owner can rename a team; anyone else gets `403`. `name` is the only field you can change: sending `slug` or any other attribute returns `422`, and a body without a `name` returns `422` with code `no_updatable_fields`. See [Error handling](/reference/error-handling).

Reference: [Update Team](/api-reference/teams/update-team) · [List Teams](/api-reference/teams/list-teams)

## Change your password with the API

In the admin, this is the **Change** button in the **Security** group of **Profile & security**, which opens the **Change password** dialog. **Reset via email instead** opens the public forgot-password form. See [Forgot your password](/guides/platform-login#forgot-your-password) for the email flow and its alpha limitation.

Use your signed-in platform access token and a flat request body. The response is `200` with a fresh access token and refresh token. Replace the tokens you stored; older refresh sessions are revoked. A team API key gets `403`. See the [change-password request and error responses](/guides/platform-login#change-a-password-while-signed-in) and the [generated endpoint](/api-reference/auth/change-password).

```bash theme={null}
CHANGE_RESPONSE=$(
  curl -sS -f -X POST "$MIO_BASE_URL/api/v1/auth/me/password/change" \
    -H "Authorization: Bearer $MIO_ACCESS_TOKEN" \
    -H "Content-Type: application/vnd.api+json" \
    -H "Accept: application/vnd.api+json" \
    -d '{"current_password":"example-password","new_password":"a-new-password"}'
)
export MIO_ACCESS_TOKEN="$(printf '%s' "$CHANGE_RESPONSE" | jq -r '.access_token')"
export MIO_REFRESH_TOKEN="$(printf '%s' "$CHANGE_RESPONSE" | jq -r '.refresh_token')"
```

## Switch teams

**In the admin:** select your avatar at the bottom of the sidebar to open the **account menu**. On a phone, tap the menu button at the top left, then your avatar at the bottom of the menu.

The row under your name and email reads **Team: {name}**. If you belong to one team, this is a static label and the **Account** page has no **Switch team** row. If you belong to several teams, open **Team: {name}** to see your teams, with the active one checked, and select the team you want. The admin switches to it, and pages such as **Hubs**, **Library**, and **API keys** show that team's data. On the **Account** page, **Open account menu** in the **Switch team** row takes you to the same menu.

The admin remembers your choice. The team stays active when you reload the page, and the next time you sign in, on any device, the admin opens the team you last switched to. If you have never switched, it opens the oldest team you own, or one of the teams you belong to if you own none.

You only see teams you are a member of. Another team appears in the list when its owner adds you (see [Not yet](#not-yet)) or when you create one with [Create Team](/api-reference/teams/create-team).

**With the API:** switch with an empty `POST`:

```bash theme={null}
curl -s -X POST "$MIO_BASE_URL/api/v1/teams/$TEAM_ID/switch" \
  -H "Authorization: Bearer $MIO_ACCESS_TOKEN" \
  -H "Accept: application/vnd.api+json" \
  | jq '.data | {id, name: .attributes.name}'
```

Success is `200` with the team. The request checks that you are a member of the team (`403` if you are not) and saves it as your **default team**. `GET /api/v1/auth/me` returns the default team as `default_team_id`, and it is the team the admin opens after you sign in.

Switching does not return a new token, and it does not change the team that a team-scoped request acts on: that still comes from the path. See the next section. A team API key cannot switch teams and gets `403`, because a key is bound to one team.

Reference: [Switch Team](/api-reference/teams/switch-team) · [Get Me](/api-reference/auth/get-me)

## The active team in API calls

The active team is a choice the admin keeps in your browser. It is not a setting on your token or your API key. The admin sends the active team's id with every request it makes, in the path of team-scoped routes and in an `X-Team-ID` header.

When you call the API yourself, the team a request acts on comes from:

| Route | Team it acts on |
| - | - |
| Team-scoped routes, such as `/api/v1/teams/{team_id}/hubs/` | The `team_id` in the path, whatever team you last switched to. Most admin routes are like this. |
| Routes with no team in the path, such as `GET /api/v1/users` | The team in the `X-Team-ID` header. Without the header, the default team recorded in your access token. |

Your access token records your default team when you sign in or refresh it, so a switch reaches the token at your next sign-in or refresh. To pick the team yourself, send the header:

```bash theme={null}
curl -s "$MIO_BASE_URL/api/v1/users" \
  -H "Authorization: Bearer $MIO_ACCESS_TOKEN" \
  -H "X-Team-ID: $TEAM_ID" \
  -H "Accept: application/vnd.api+json" \
  | jq -r '.data[] | "\(.attributes.first_name) \(.attributes.last_name)"'
```

A request with no team in the header or the token returns `400`, and a team you are not a member of returns `403`.

A team API key always acts on its own team. A path or an `X-Team-ID` header that names a different team returns `403`. See [API keys](/reference/api-keys) and [Tenancy](/concepts/tenancy).

## Not yet

The admin is in alpha. These are not on the **Account** page yet:

* **Inviting team members by email** (MIO-3900). The admin lists the team's people read only and has no invites. With the API, the team owner can add someone who already has an account, by their user id. They can find their id in `data.id` of `GET /api/v1/auth/me`.

  ```bash theme={null}
  curl -s -X POST "$MIO_BASE_URL/api/v1/teams/$TEAM_ID/members" \
    -H "Authorization: Bearer $MIO_ACCESS_TOKEN" \
    -H "Content-Type: application/vnd.api+json" \
    -H "Accept: application/vnd.api+json" \
    -d '{
      "data": {
        "type": "team_members",
        "attributes": {
          "user_id": "<their user id>"
        }
      }
    }'
  ```

  Success is `201`. Someone who is already a member returns `409`, and anyone but the owner gets `403`. A team API key can add a member too, but not give them a role: a key request that sets `role_id` returns `403`, so assigning a role needs the owner's signed-in session. The new member can switch to the team, but only the owner can rename it or manage its API keys. See [Add Member](/api-reference/teams/add-member).

  **Letting a member read the contact directory.** The owner can give a member a reduced, read-only view of the team's contacts with the `contacts.read` team permission. With the owner's signed-in session (team API keys get `403` on these routes):

  1. Create a role for the team: `POST /api/v1/roles` with `team_id` set to your team.
  2. Attach the permission: `POST /api/v1/roles/{role_id}/permissions` with `{"slug": "contacts.read"}`. A team role accepts only team-scoped permissions; anything else, such as `users.read`, returns `422` with code `permission_not_team_scoped`.
  3. Give the member the role: `PATCH /api/v1/teams/{team_id}/members/{user_id}` with `{"data": {"type": "team_members", "attributes": {"role_id": "<role id>"}}}`. Send `"role_id": null` to take it away.

  The member can then call `GET /api/v1/teams/{team_id}/contact-directory`, which lists the team's live contacts with six fields only: `contact_id`, `first_name`, `last_name`, `email`, `source` and `created_at`. It never includes deleted contacts, and it supports `filter[email]`, `filter[source]`, `sort` and cursor pagination. Access is checked against the member's current role on every request, so removing the permission, the role or the membership takes effect straight away. The owner can call it too; the full contact routes stay owner-only.

  **Who can change the team's media.** Media follows the same team roles. Any team member can read the media library. Editing needs the team owner, or a member whose team role holds the `media.edit` permission, which you attach exactly like `contacts.read` above. Editing covers uploading, renaming and updating files, folders and playlists, attaching and detaching, transcripts, transcoding, and publishing to or unpublishing from hubs. Deleting files, folders and playlists, and replacing a file's media, stay with the team owner. A member without `media.edit` gets `403` on an edit, and a member with it gets `403` on a delete. A full-scope team API key keeps full media access, deletes included, so the mio CLI's media commands keep working. Hub owners and admins signed in to a hub keep their current editor access, and the MCP media tools stay owner-only.

  When this shipped, every existing member without a role was given a team role named "Media editor" that holds `media.edit`, so nobody lost editing. A member whose role is a platform system role keeps that role and can read the team's media but not change it. A member holds one role, so giving them a team role replaces their platform role.
* **Profile pictures.** You cannot upload an avatar, in the admin or with the API. The admin shows your initials.
* **Deleting a team.** The admin has no button for it. The API has `DELETE /api/v1/teams/{team_id}`, for the owner with a signed-in session only (team API keys get `403`). It refuses with `409` while the team still has hubs, contacts, or API keys, and the error's `meta` counts them. See [Delete Team](/api-reference/teams/delete-team).

## Next steps

* [Tenancy](/concepts/tenancy): how teams and hubs scope your data.
* [Authentication](/concepts/authentication): when to use a platform JWT, a contact JWT, or a team API key.
* [API keys](/reference/api-keys): create a team API key for your integration or the CLI.
* [Sign in as a creator](/guides/platform-login): the platform sign-in flow for your own tools.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.