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

# Account

> Profile, API tokens, connected applications, referrals and team seats.

23 tools. Each one is also a REST route and a CLI command, from the same definition: the same input, the same output, the same errors.

| Tool                                                | What it does                             | Kind                                                  |
| --------------------------------------------------- | ---------------------------------------- | ----------------------------------------------------- |
| [`get_consent_request`](#get_consent_request)       | Describe a pending consent request       | Read · idempotent · no outside service                |
| [`get_entitlements`](#get_entitlements)             | What your plan grants                    | Read · idempotent · no outside service                |
| [`get_leaderboard`](#get_leaderboard)               | The week's board                         | Read · idempotent · no outside service                |
| [`get_me`](#get_me)                                 | The signed-in account                    | Read · idempotent · no outside service                |
| [`get_my_profile`](#get_my_profile)                 | Your profile                             | Read · idempotent · no outside service                |
| [`get_public_profile`](#get_public_profile)         | Someone's profile                        | Read · idempotent · no outside service                |
| [`list_api_tokens`](#list_api_tokens)               | List your API tokens                     | Read · idempotent · no outside service                |
| [`list_connections`](#list_connections)             | List the applications you have connected | Read · idempotent · no outside service                |
| [`list_followers`](#list_followers)                 | Who follows you                          | Read · idempotent · no outside service                |
| [`list_following`](#list_following)                 | Who you follow                           | Read · idempotent · no outside service                |
| [`list_referral_invites`](#list_referral_invites)   | List your invites                        | Read · idempotent · no outside service                |
| [`search_users`](#search_users)                     | Find someone to share with               | Read · idempotent · no outside service                |
| [`create_api_token`](#create_api_token)             | Create an API token                      | Write · no outside service                            |
| [`create_referral_invite`](#create_referral_invite) | Create an invite                         | Write · no outside service                            |
| [`decide_consent_request`](#decide_consent_request) | Approve or refuse a consent request      | Write · no outside service                            |
| [`follow_profile`](#follow_profile)                 | Follow someone                           | Write · no outside service                            |
| [`grant_team_seat`](#grant_team_seat)               | Seat someone on your team plan           | Write · no outside service                            |
| [`redeem_referral_invite`](#redeem_referral_invite) | Redeem an invite code                    | Write · no outside service                            |
| [`revoke_api_token`](#revoke_api_token)             | Revoke an API token                      | Write · destructive · idempotent · no outside service |
| [`revoke_connection`](#revoke_connection)           | Disconnect an application                | Write · destructive · idempotent · no outside service |
| [`revoke_team_seat`](#revoke_team_seat)             | Take a seat back                         | Write · destructive · idempotent · no outside service |
| [`set_profile_visibility`](#set_profile_visibility) | Open or close your profile               | Write · idempotent · no outside service               |
| [`unfollow_profile`](#unfollow_profile)             | Stop following someone                   | Write · destructive · idempotent · no outside service |

## get\_consent\_request

**Describe a pending consent request.**

What the consent screen shows, and nothing more: who is asking, where they will be sent back to, and whether you have approved them before. Returns 404 once the request has been answered or has expired: a consent screen for a dead request is a trap.

|           |                                                                                 |
| --------- | ------------------------------------------------------------------------------- |
| Kind      | Read · idempotent · no outside service                                          |
| Auth      | Bearer token: a personal API token (`pc_…`) or an OAuth access token (`pcat_…`) |
| REST      | `GET https://api.doers.sh/v2/connections/requests/{requestId}`                  |
| CLI       | `doers connections get-consent-request`                                         |
| Touches   | no table directly                                                               |
| Operation | `getConsentRequest`                                                             |

### Input

| Field              | Type   | Required | Default | Allowed values      | Description                      |
| ------------------ | ------ | -------- | ------- | ------------------- | -------------------------------- |
| `requestId` (path) | string | yes      |         | 1 to 128 characters | The consent request's opaque id. |

### Output

<Accordion title="Output fields">
  | Field                    | Type           | Allowed values | Description                                                  |
  | ------------------------ | -------------- | -------------- | ------------------------------------------------------------ |
  | `request`                | object         |                |                                                              |
  | `request.clientName`     | string         |                |                                                              |
  | `request.redirectHost`   | string         |                |                                                              |
  | `request.localOnly`      | boolean        |                | `true` when the callback is on this machine.                 |
  | `request.connectedSince` | number \| null |                | When this application was last approved, or `null` if never. |
</Accordion>

### Example

<CodeGroup>
  ```json Request theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
      "name": "get_consent_request",
      "arguments": {
        "requestId": "1f58b914-5b24-4108-87ac-38887338b3ea"
      }
    }
  }
  ```

  ```json Response theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "result": {
      "content": [
        {
          "type": "text",
          "text": "Notes for the Acme launch. is asking for access."
        }
      ],
      "structuredContent": {
        "request": {
          "clientName": "Notes for the Acme launch.",
          "redirectHost": "Notes for the Acme launch.",
          "localOnly": true,
          "connectedSince": 1790069400000
        }
      }
    }
  }
  ```

  ```bash CLI theme={null}
  doers connections get-consent-request --request-id 1f58b914-5b24-4108-87ac-38887338b3ea
  ```
</CodeGroup>

## get\_entitlements

**What your plan grants.**

Your plan, where it comes from, its features as of now, and the seats you hold when it is a team plan. A lifetime purchase keeps receiving what its plan gains and never becomes a higher plan on its own; a seat grants the holder's plan for as long as they hold it.

|           |                                                                                 |
| --------- | ------------------------------------------------------------------------------- |
| Kind      | Read · idempotent · no outside service                                          |
| Auth      | Bearer token: a personal API token (`pc_…`) or an OAuth access token (`pcat_…`) |
| REST      | `GET https://api.doers.sh/v2/billing/entitlements`                              |
| CLI       | `doers billing get-entitlements`                                                |
| Touches   | `user`, `workspaceMembers`, `workspaces`                                        |
| Operation | `getEntitlements`                                                               |

### Input

This tool takes no arguments.

### Output

<Accordion title="Output fields">
  | Field                        | Type           | Allowed values                             | Description                                  |
  | ---------------------------- | -------------- | ------------------------------------------ | -------------------------------------------- |
  | `entitlement`                | object         |                                            |                                              |
  | `entitlement.plan`           | string         | `free`, `pro`, `team`                      |                                              |
  | `entitlement.source`         | string \| null | `subscription`, `lifetime`, `seat`         | Where the plan comes from; `null` on free.   |
  | `entitlement.features`       | string\[]      | each: `username-reservation`, `team-seats` | The plan's features as of now, never frozen. |
  | `entitlement.seats`          | object \| null |                                            | `null` unless the account holds a team plan. |
  | `entitlement.seats.included` | integer        | 0 to 9007199254740991                      |                                              |
  | `entitlement.seats.used`     | integer        | 0 to 9007199254740991                      |                                              |
  | `entitlement.seats.members`  | string\[]      |                                            | The seated people, by handle.                |
</Accordion>

### Example

<CodeGroup>
  ```json Request theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
      "name": "get_entitlements",
      "arguments": {}
    }
  }
  ```

  ```json Response theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "result": {
      "content": [
        {
          "type": "text",
          "text": "free (subscription) · 3/3 seats"
        }
      ],
      "structuredContent": {
        "entitlement": {
          "plan": "free",
          "source": "subscription",
          "features": ["username-reservation"],
          "seats": {
            "included": 3,
            "used": 3,
            "members": ["Notes for the Acme launch."]
          }
        }
      }
    }
  }
  ```

  ```bash CLI theme={null}
  doers billing get-entitlements
  ```
</CodeGroup>

## get\_leaderboard

**The week's board.**

Who opted in, ranked on verified focus time and consistency (never on how many tasks they ticked) under a named, versioned rule. Global, or only the people you follow and you. This week, or last week's recap.

|           |                                                                                 |
| --------- | ------------------------------------------------------------------------------- |
| Kind      | Read · idempotent · no outside service                                          |
| Auth      | Bearer token: a personal API token (`pc_…`) or an OAuth access token (`pcat_…`) |
| REST      | `GET https://api.doers.sh/v2/leaderboard`                                       |
| CLI       | `doers profiles get-leaderboard`                                                |
| Touches   | `follows`, `profiles`, `user`, `workSessions`                                   |
| Operation | `getLeaderboard`                                                                |

### Input

| Field           | Type   | Required | Default | Allowed values        | Description                                                  |
| --------------- | ------ | -------- | ------- | --------------------- | ------------------------------------------------------------ |
| `scope` (query) | string | yes      |         | `global`, `following` | *No description in the registry.*                            |
| `week` (query)  | string | yes      |         | `current`, `previous` | This week, or last week's recap. Weeks start on Monday, UTC. |

### Output

<Accordion title="Output fields">
  | Field                                | Type           | Allowed values        | Description                                                  |
  | ------------------------------------ | -------------- | --------------------- | ------------------------------------------------------------ |
  | `leaderboard`                        | object         |                       |                                                              |
  | `leaderboard.version`                | string         |                       | The ranking rule this board was ranked under.                |
  | `leaderboard.scope`                  | string         | `global`, `following` |                                                              |
  | `leaderboard.week`                   | string         | `current`, `previous` | This week, or last week's recap. Weeks start on Monday, UTC. |
  | `leaderboard.weekStart`              | string         | `YYYY-MM-DD`          | Local day key, `YYYY-MM-DD`.                                 |
  | `leaderboard.entries`                | object\[]      |                       |                                                              |
  | `leaderboard.entries[].rank`         | integer        | 1 to 9007199254740991 | Competition ranking: equal activity shares a rank.           |
  | `leaderboard.entries[].username`     | string         |                       |                                                              |
  | `leaderboard.entries[].name`         | string         |                       |                                                              |
  | `leaderboard.entries[].image`        | string \| null |                       |                                                              |
  | `leaderboard.entries[].focusMinutes` | integer        | 0 to 9007199254740991 |                                                              |
  | `leaderboard.entries[].activeDays`   | integer        | 0 to 9007199254740991 |                                                              |
  | `leaderboard.entries[].streakDays`   | integer        | 0 to 9007199254740991 | The longest run of active days in the week.                  |
  | `leaderboard.entries[].isMe`         | boolean        |                       |                                                              |
  | `leaderboard.me`                     | object \| null |                       | `null` unless you opted in.                                  |
  | `leaderboard.me.rank`                | integer        | 1 to 9007199254740991 | Competition ranking: equal activity shares a rank.           |
  | `leaderboard.me.username`            | string         |                       |                                                              |
  | `leaderboard.me.name`                | string         |                       |                                                              |
  | `leaderboard.me.image`               | string \| null |                       |                                                              |
  | `leaderboard.me.focusMinutes`        | integer        | 0 to 9007199254740991 |                                                              |
  | `leaderboard.me.activeDays`          | integer        | 0 to 9007199254740991 |                                                              |
  | `leaderboard.me.streakDays`          | integer        | 0 to 9007199254740991 | The longest run of active days in the week.                  |
  | `leaderboard.me.isMe`                | boolean        |                       |                                                              |
</Accordion>

### Example

<CodeGroup>
  ```json Request theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
      "name": "get_leaderboard",
      "arguments": {
        "scope": "global",
        "week": "current"
      }
    }
  }
  ```

  ```json Response theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "result": {
      "content": [
        {
          "type": "text",
          "text": "3. @ada · 30 min · 3 day(s)"
        }
      ],
      "structuredContent": {
        "leaderboard": {
          "version": "Notes for the Acme launch.",
          "scope": "global",
          "week": "current",
          "weekStart": "2026-09-22",
          "entries": [
            {
              "rank": 3,
              "username": "ada",
              "name": "Acme",
              "image": "https://acme.example/ada.png",
              "focusMinutes": 30,
              "activeDays": 3,
              "streakDays": 3,
              "isMe": true
            }
          ],
          "me": {
            "rank": 3,
            "username": "ada",
            "name": "Acme",
            "image": "https://acme.example/ada.png",
            "focusMinutes": 30,
            "activeDays": 3,
            "streakDays": 3,
            "isMe": true
          }
        }
      }
    }
  }
  ```

  ```bash CLI theme={null}
  doers profiles get-leaderboard --scope global --week current
  ```
</CodeGroup>

## get\_me

**The signed-in account.**

The caller's own profile. Distinct from the session endpoint, which says who you are but not when you may next change your username: a rule this API enforces and only this API knows the shape of.

`nextUsernameChangeAt` is `null` when the username has never been set, which is the one case with no cooldown.

|           |                                                                                 |
| --------- | ------------------------------------------------------------------------------- |
| Kind      | Read · idempotent · no outside service                                          |
| Auth      | Bearer token: a personal API token (`pc_…`) or an OAuth access token (`pcat_…`) |
| REST      | `GET https://api.doers.sh/v2/users/me`                                          |
| CLI       | `doers users get-me`                                                            |
| Touches   | `user`                                                                          |
| Operation | `getMe`                                                                         |

### Input

This tool takes no arguments.

### Output

<Accordion title="Output fields">
  | Field                     | Type           | Allowed values | Description                                                           |
  | ------------------------- | -------------- | -------------- | --------------------------------------------------------------------- |
  | `me`                      | object         |                |                                                                       |
  | `me.id`                   | string         |                |                                                                       |
  | `me.name`                 | string \| null |                |                                                                       |
  | `me.email`                | string \| null |                |                                                                       |
  | `me.username`             | string \| null |                |                                                                       |
  | `me.image`                | string \| null |                |                                                                       |
  | `me.usernameUpdatedAt`    | number \| null |                |                                                                       |
  | `me.nextUsernameChangeAt` | number \| null |                | When the username may next change. `null` when it has never been set. |
</Accordion>

### Example

<CodeGroup>
  ```json Request theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
      "name": "get_me",
      "arguments": {}
    }
  }
  ```

  ```json Response theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "result": {
      "content": [
        {
          "type": "text",
          "text": "OK: ada."
        }
      ],
      "structuredContent": {
        "me": {
          "id": "2744ccd1-0c75-43bd-836a-d890f9dd5cab",
          "name": "Acme",
          "email": "ada@acme.example",
          "username": "ada",
          "image": "https://acme.example/ada.png",
          "usernameUpdatedAt": 1790069400000,
          "nextUsernameChangeAt": 1790069400000
        }
      }
    }
  }
  ```

  ```bash CLI theme={null}
  doers users get-me
  ```
</CodeGroup>

## get\_my\_profile

**Your profile.**

Your handle, whether you are visible, your founding number from signup order, and how many follow you and you follow.

|           |                                                                                 |
| --------- | ------------------------------------------------------------------------------- |
| Kind      | Read · idempotent · no outside service                                          |
| Auth      | Bearer token: a personal API token (`pc_…`) or an OAuth access token (`pcat_…`) |
| REST      | `GET https://api.doers.sh/v2/profiles/me`                                       |
| CLI       | `doers profiles get-my`                                                         |
| Touches   | `follows`, `profiles`, `user`, `workSessions`                                   |
| Operation | `getMyProfile`                                                                  |

### Input

This tool takes no arguments.

### Output

<Accordion title="Output fields">
  | Field                      | Type            | Allowed values        | Description                                  |
  | -------------------------- | --------------- | --------------------- | -------------------------------------------- |
  | `profile`                  | object          |                       |                                              |
  | `profile.username`         | string \| null  |                       |                                              |
  | `profile.name`             | string          |                       |                                              |
  | `profile.image`            | string \| null  |                       |                                              |
  | `profile.visibility`       | string          | `private`, `public`   | Private until its owner says otherwise.      |
  | `profile.leaderboard`      | boolean         |                       | Opted into the leaderboards. Off by default. |
  | `profile.foundingNumber`   | integer         | 1 to 9007199254740991 |                                              |
  | `profile.isFoundingMember` | boolean \| null |                       |                                              |
  | `profile.followers`        | integer         | 0 to 9007199254740991 |                                              |
  | `profile.following`        | integer         | 0 to 9007199254740991 |                                              |
</Accordion>

### Example

<CodeGroup>
  ```json Request theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
      "name": "get_my_profile",
      "arguments": {}
    }
  }
  ```

  ```json Response theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "result": {
      "content": [
        {
          "type": "text",
          "text": "@ada · private · #3"
        }
      ],
      "structuredContent": {
        "profile": {
          "username": "ada",
          "name": "Acme",
          "image": "https://acme.example/ada.png",
          "visibility": "private",
          "leaderboard": true,
          "foundingNumber": 3,
          "isFoundingMember": true,
          "followers": 3,
          "following": 3
        }
      }
    }
  }
  ```

  ```bash CLI theme={null}
  doers profiles get-my
  ```
</CodeGroup>

## get\_public\_profile

**Someone's profile.**

A public profile, or your own whatever its visibility. A private one is not found.

|           |                                                                                 |
| --------- | ------------------------------------------------------------------------------- |
| Kind      | Read · idempotent · no outside service                                          |
| Auth      | Bearer token: a personal API token (`pc_…`) or an OAuth access token (`pcat_…`) |
| REST      | `GET https://api.doers.sh/v2/people/{username}`                                 |
| CLI       | `doers profiles get-public`                                                     |
| Touches   | `follows`, `profiles`, `user`, `workSessions`                                   |
| Operation | `getPublicProfile`                                                              |

### Input

| Field             | Type   | Required | Default | Allowed values | Description                       |
| ----------------- | ------ | -------- | ------- | -------------- | --------------------------------- |
| `username` (path) | string | yes      |         |                | *No description in the registry.* |

### Output

<Accordion title="Output fields">
  | Field                                 | Type            | Allowed values        | Description                                    |
  | ------------------------------------- | --------------- | --------------------- | ---------------------------------------------- |
  | `profile`                             | object          |                       |                                                |
  | `profile.username`                    | string          |                       |                                                |
  | `profile.name`                        | string          |                       |                                                |
  | `profile.image`                       | string \| null  |                       |                                                |
  | `profile.foundingNumber`              | integer         | 1 to 9007199254740991 | Signup order: the first account is 1.          |
  | `profile.isFoundingMember`            | boolean \| null |                       | `null` while the founding cutoff is not named. |
  | `profile.followers`                   | integer         | 0 to 9007199254740991 |                                                |
  | `profile.following`                   | integer         | 0 to 9007199254740991 |                                                |
  | `profile.isFollowed`                  | boolean         |                       | Whether the caller follows this profile.       |
  | `profile.stats`                       | object \| null  |                       | `null` when the profile is not public.         |
  | `profile.stats.focusMinutesLast7Days` | integer         | 0 to 9007199254740991 |                                                |
  | `profile.stats.activeDaysLast28`      | integer         | 0 to 9007199254740991 |                                                |
  | `profile.stats.streakDays`            | integer         | 0 to 9007199254740991 |                                                |
</Accordion>

### Example

<CodeGroup>
  ```json Request theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
      "name": "get_public_profile",
      "arguments": {
        "username": "ada"
      }
    }
  }
  ```

  ```json Response theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "result": {
      "content": [
        {
          "type": "text",
          "text": "@ada · 3 follower(s) · 30 min this week"
        }
      ],
      "structuredContent": {
        "profile": {
          "username": "ada",
          "name": "Acme",
          "image": "https://acme.example/ada.png",
          "foundingNumber": 3,
          "isFoundingMember": true,
          "followers": 3,
          "following": 3,
          "isFollowed": true,
          "stats": {
            "focusMinutesLast7Days": 30,
            "activeDaysLast28": 3,
            "streakDays": 3
          }
        }
      }
    }
  }
  ```

  ```bash CLI theme={null}
  doers profiles get-public ada
  ```
</CodeGroup>

## list\_api\_tokens

**List your API tokens.**

Newest first. The token itself is **not** here and cannot be: only its hash is stored, so a lost token is replaced rather than recovered.

|           |                                                                                 |
| --------- | ------------------------------------------------------------------------------- |
| Kind      | Read · idempotent · no outside service                                          |
| Auth      | Bearer token: a personal API token (`pc_…`) or an OAuth access token (`pcat_…`) |
| REST      | `GET https://api.doers.sh/v2/tokens`                                            |
| CLI       | `doers tokens list-api`                                                         |
| Touches   | `apiTokens`                                                                     |
| Operation | `listApiTokens`                                                                 |

### Input

| Field                    | Type    | Required | Default | Allowed values | Description                       |
| ------------------------ | ------- | -------- | ------- | -------------- | --------------------------------- |
| `includeRevoked` (query) | boolean | no       | `false` |                | *No description in the registry.* |

### Output

<Accordion title="Output fields">
  | Field                 | Type           | Allowed values | Description                            |
  | --------------------- | -------------- | -------------- | -------------------------------------- |
  | `tokens`              | object\[]      |                |                                        |
  | `tokens[].id`         | string         |                |                                        |
  | `tokens[].label`      | string         |                |                                        |
  | `tokens[].createdAt`  | number         |                | Epoch milliseconds.                    |
  | `tokens[].lastUsedAt` | number \| null |                | `null` if it has never been presented. |
  | `tokens[].revokedAt`  | number \| null |                |                                        |
</Accordion>

### Example

<CodeGroup>
  ```json Request theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
      "name": "list_api_tokens",
      "arguments": {
        "includeRevoked": false
      }
    }
  }
  ```

  ```json Response theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "result": {
      "content": [
        {
          "type": "text",
          "text": "- [3c469e9d-6c58-45d3-8a43-f353d4f88e61] Acme"
        }
      ],
      "structuredContent": {
        "tokens": [
          {
            "id": "3c469e9d-6c58-45d3-8a43-f353d4f88e61",
            "label": "Acme",
            "createdAt": 1790069400000,
            "lastUsedAt": 1790069400000,
            "revokedAt": 1790069400000
          }
        ]
      }
    }
  }
  ```

  ```bash CLI theme={null}
  doers tokens list-api --include-revoked false
  ```
</CodeGroup>

## list\_connections

**List the applications you have connected.**

Everything holding a live grant, most recently used first.

|           |                                                                                 |
| --------- | ------------------------------------------------------------------------------- |
| Kind      | Read · idempotent · no outside service                                          |
| Auth      | Bearer token: a personal API token (`pc_…`) or an OAuth access token (`pcat_…`) |
| REST      | `GET https://api.doers.sh/v2/connections`                                       |
| CLI       | `doers connections list`                                                        |
| Touches   | no table directly                                                               |
| Operation | `listConnections`                                                               |

### Input

This tool takes no arguments.

### Output

<Accordion title="Output fields">
  | Field                      | Type           | Allowed values | Description         |
  | -------------------------- | -------------- | -------------- | ------------------- |
  | `connections`              | object\[]      |                |                     |
  | `connections[].id`         | string         |                |                     |
  | `connections[].clientName` | string         |                |                     |
  | `connections[].clientUri`  | string \| null |                |                     |
  | `connections[].scope`      | string         |                |                     |
  | `connections[].createdAt`  | number         |                | Epoch milliseconds. |
  | `connections[].lastUsedAt` | number         |                | Epoch milliseconds. |
</Accordion>

### Example

<CodeGroup>
  ```json Request theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
      "name": "list_connections",
      "arguments": {}
    }
  }
  ```

  ```json Response theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "result": {
      "content": [
        {
          "type": "text",
          "text": "- [b38d9d16-8c3a-4df1-86f4-f249b81adaef] Notes for the Acme launch."
        }
      ],
      "structuredContent": {
        "connections": [
          {
            "id": "b38d9d16-8c3a-4df1-86f4-f249b81adaef",
            "clientName": "Notes for the Acme launch.",
            "clientUri": "Notes for the Acme launch.",
            "scope": "Notes for the Acme launch.",
            "createdAt": 1790069400000,
            "lastUsedAt": 1790069400000
          }
        ]
      }
    }
  }
  ```

  ```bash CLI theme={null}
  doers connections list
  ```
</CodeGroup>

## list\_followers

**Who follows you.**

Each as a profile; a private follower shows a handle and no stats.

|           |                                                                                 |
| --------- | ------------------------------------------------------------------------------- |
| Kind      | Read · idempotent · no outside service                                          |
| Auth      | Bearer token: a personal API token (`pc_…`) or an OAuth access token (`pcat_…`) |
| REST      | `GET https://api.doers.sh/v2/profiles/me/followers`                             |
| CLI       | `doers profiles list-followers`                                                 |
| Touches   | `follows`, `profiles`, `user`, `workSessions`                                   |
| Operation | `listFollowers`                                                                 |

### Input

This tool takes no arguments.

### Output

<Accordion title="Output fields">
  | Field                                  | Type            | Allowed values        | Description                                    |
  | -------------------------------------- | --------------- | --------------------- | ---------------------------------------------- |
  | `people`                               | object\[]       |                       |                                                |
  | `people[].username`                    | string          |                       |                                                |
  | `people[].name`                        | string          |                       |                                                |
  | `people[].image`                       | string \| null  |                       |                                                |
  | `people[].foundingNumber`              | integer         | 1 to 9007199254740991 | Signup order: the first account is 1.          |
  | `people[].isFoundingMember`            | boolean \| null |                       | `null` while the founding cutoff is not named. |
  | `people[].followers`                   | integer         | 0 to 9007199254740991 |                                                |
  | `people[].following`                   | integer         | 0 to 9007199254740991 |                                                |
  | `people[].isFollowed`                  | boolean         |                       | Whether the caller follows this profile.       |
  | `people[].stats`                       | object \| null  |                       | `null` when the profile is not public.         |
  | `people[].stats.focusMinutesLast7Days` | integer         | 0 to 9007199254740991 |                                                |
  | `people[].stats.activeDaysLast28`      | integer         | 0 to 9007199254740991 |                                                |
  | `people[].stats.streakDays`            | integer         | 0 to 9007199254740991 |                                                |
</Accordion>

### Example

<CodeGroup>
  ```json Request theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
      "name": "list_followers",
      "arguments": {}
    }
  }
  ```

  ```json Response theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "result": {
      "content": [
        {
          "type": "text",
          "text": "- @ada Acme"
        }
      ],
      "structuredContent": {
        "people": [
          {
            "username": "ada",
            "name": "Acme",
            "image": "https://acme.example/ada.png",
            "foundingNumber": 3,
            "isFoundingMember": true,
            "followers": 3,
            "following": 3,
            "isFollowed": true,
            "stats": {
              "focusMinutesLast7Days": 30,
              "activeDaysLast28": 3,
              "streakDays": 3
            }
          }
        ]
      }
    }
  }
  ```

  ```bash CLI theme={null}
  doers profiles list-followers
  ```
</CodeGroup>

## list\_following

**Who you follow.**

Each as a profile; one that went private since shows a handle and no stats.

|           |                                                                                 |
| --------- | ------------------------------------------------------------------------------- |
| Kind      | Read · idempotent · no outside service                                          |
| Auth      | Bearer token: a personal API token (`pc_…`) or an OAuth access token (`pcat_…`) |
| REST      | `GET https://api.doers.sh/v2/profiles/me/following`                             |
| CLI       | `doers profiles list-following`                                                 |
| Touches   | `follows`, `profiles`, `user`, `workSessions`                                   |
| Operation | `listFollowing`                                                                 |

### Input

This tool takes no arguments.

### Output

<Accordion title="Output fields">
  | Field                                  | Type            | Allowed values        | Description                                    |
  | -------------------------------------- | --------------- | --------------------- | ---------------------------------------------- |
  | `people`                               | object\[]       |                       |                                                |
  | `people[].username`                    | string          |                       |                                                |
  | `people[].name`                        | string          |                       |                                                |
  | `people[].image`                       | string \| null  |                       |                                                |
  | `people[].foundingNumber`              | integer         | 1 to 9007199254740991 | Signup order: the first account is 1.          |
  | `people[].isFoundingMember`            | boolean \| null |                       | `null` while the founding cutoff is not named. |
  | `people[].followers`                   | integer         | 0 to 9007199254740991 |                                                |
  | `people[].following`                   | integer         | 0 to 9007199254740991 |                                                |
  | `people[].isFollowed`                  | boolean         |                       | Whether the caller follows this profile.       |
  | `people[].stats`                       | object \| null  |                       | `null` when the profile is not public.         |
  | `people[].stats.focusMinutesLast7Days` | integer         | 0 to 9007199254740991 |                                                |
  | `people[].stats.activeDaysLast28`      | integer         | 0 to 9007199254740991 |                                                |
  | `people[].stats.streakDays`            | integer         | 0 to 9007199254740991 |                                                |
</Accordion>

### Example

<CodeGroup>
  ```json Request theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
      "name": "list_following",
      "arguments": {}
    }
  }
  ```

  ```json Response theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "result": {
      "content": [
        {
          "type": "text",
          "text": "- @ada Acme"
        }
      ],
      "structuredContent": {
        "people": [
          {
            "username": "ada",
            "name": "Acme",
            "image": "https://acme.example/ada.png",
            "foundingNumber": 3,
            "isFoundingMember": true,
            "followers": 3,
            "following": 3,
            "isFollowed": true,
            "stats": {
              "focusMinutesLast7Days": 30,
              "activeDaysLast28": 3,
              "streakDays": 3
            }
          }
        ]
      }
    }
  }
  ```

  ```bash CLI theme={null}
  doers profiles list-following
  ```
</CodeGroup>

## list\_referral\_invites

**List your invites.**

Every grant you made, newest first, with how many more you may make. The code itself is **not** here and cannot be: only its hash is stored, so a lost code is replaced, not recovered.

|           |                                                                                 |
| --------- | ------------------------------------------------------------------------------- |
| Kind      | Read · idempotent · no outside service                                          |
| Auth      | Bearer token: a personal API token (`pc_…`) or an OAuth access token (`pcat_…`) |
| REST      | `GET https://api.doers.sh/v2/referrals`                                         |
| CLI       | `doers referrals list-referral-invites`                                         |
| Touches   | `creemCustomer`, `creemSubscription`, `invites`                                 |
| Operation | `listReferralInvites`                                                           |

### Input

This tool takes no arguments.

### Output

<Accordion title="Output fields">
  | Field                  | Type           | Allowed values                | Description                                  |
  | ---------------------- | -------------- | ----------------------------- | -------------------------------------------- |
  | `invites`              | object\[]      |                               |                                              |
  | `invites[].id`         | string         |                               |                                              |
  | `invites[].createdAt`  | number         |                               | Epoch milliseconds.                          |
  | `invites[].expiresAt`  | number         |                               | Epoch milliseconds.                          |
  | `invites[].redeemedAt` | number \| null |                               | `null` while the code is unredeemed.         |
  | `invites[].status`     | string         | `open`, `redeemed`, `expired` | Derived from the two instants and the clock. |
  | `remaining`            | integer        | 0 to 9007199254740991         | Grants you may still make.                   |
</Accordion>

### Example

<CodeGroup>
  ```json Request theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
      "name": "list_referral_invites",
      "arguments": {}
    }
  }
  ```

  ```json Response theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "result": {
      "content": [
        {
          "type": "text",
          "text": "1 invite(s), 3 more to give."
        }
      ],
      "structuredContent": {
        "invites": [
          {
            "id": "5014f9af-3a68-4fdd-84a7-75c1c4c532ee",
            "createdAt": 1790069400000,
            "expiresAt": 1790069400000,
            "redeemedAt": 1790069400000,
            "status": "open"
          }
        ],
        "remaining": 3
      }
    }
  }
  ```

  ```bash CLI theme={null}
  doers referrals list-referral-invites
  ```
</CodeGroup>

## search\_users

**Find someone to share with.**

Deliberately narrow: a username prefix, or a **whole** email address. There is no fuzzy match and no name search, because a directory of everyone is what this must not be. An address is echoed back only when it was already known to the caller: a prefix search never reveals one. At most 8 are returned.

|           |                                                                                 |
| --------- | ------------------------------------------------------------------------------- |
| Kind      | Read · idempotent · no outside service                                          |
| Auth      | Bearer token: a personal API token (`pc_…`) or an OAuth access token (`pcat_…`) |
| REST      | `GET https://api.doers.sh/v2/users/search`                                      |
| CLI       | `doers users search`                                                            |
| Touches   | `user`                                                                          |
| Operation | `searchUsers`                                                                   |

### Input

| Field           | Type   | Required | Default | Allowed values      | Description                       |
| --------------- | ------ | -------- | ------- | ------------------- | --------------------------------- |
| `query` (query) | string | yes      |         | 2 to 200 characters | *No description in the registry.* |

### Output

<Accordion title="Output fields">
  | Field              | Type           | Allowed values | Description |
  | ------------------ | -------------- | -------------- | ----------- |
  | `users`            | object\[]      |                |             |
  | `users[].id`       | string         |                |             |
  | `users[].username` | string \| null |                |             |
  | `users[].name`     | string \| null |                |             |
  | `users[].email`    | string \| null |                |             |
  | `users[].image`    | string \| null |                |             |
</Accordion>

### Example

<CodeGroup>
  ```json Request theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
      "name": "search_users",
      "arguments": {
        "query": "Acme"
      }
    }
  }
  ```

  ```json Response theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "result": {
      "content": [
        {
          "type": "text",
          "text": "- [04f8996d-a763-47a9-89b1-028ee3007569] ada"
        }
      ],
      "structuredContent": {
        "users": [
          {
            "id": "04f8996d-a763-47a9-89b1-028ee3007569",
            "username": "ada",
            "name": "Acme",
            "email": "ada@acme.example",
            "image": "https://acme.example/ada.png"
          }
        ]
      }
    }
  }
  ```

  ```bash CLI theme={null}
  doers users search --query Acme
  ```
</CodeGroup>

## create\_api\_token

**Create an API token.**

Returns the token in `secret`, **once**. It is not recoverable afterwards, so it has to be stored by the caller at this point or created again.

|           |                                                                                 |
| --------- | ------------------------------------------------------------------------------- |
| Kind      | Write · no outside service                                                      |
| Auth      | Bearer token: a personal API token (`pc_…`) or an OAuth access token (`pcat_…`) |
| REST      | `POST https://api.doers.sh/v2/tokens`                                           |
| CLI       | `doers tokens create-api`                                                       |
| Touches   | `apiTokens`                                                                     |
| Operation | `createApiToken`                                                                |

### Input

| Field   | Type   | Required | Default | Allowed values      | Description                       |
| ------- | ------ | -------- | ------- | ------------------- | --------------------------------- |
| `label` | string | no       |         | 0 to 200 characters | *No description in the registry.* |

### Output

<Accordion title="Output fields">
  | Field              | Type           | Allowed values | Description                                   |
  | ------------------ | -------------- | -------------- | --------------------------------------------- |
  | `token`            | object         |                |                                               |
  | `token.id`         | string         |                |                                               |
  | `token.label`      | string         |                |                                               |
  | `token.createdAt`  | number         |                | Epoch milliseconds.                           |
  | `token.lastUsedAt` | number \| null |                | `null` if it has never been presented.        |
  | `token.revokedAt`  | number \| null |                |                                               |
  | `secret`           | string         |                | The bearer token. Shown once and never again. |
</Accordion>

### Example

<CodeGroup>
  ```json Request theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
      "name": "create_api_token",
      "arguments": {
        "label": "Acme"
      }
    }
  }
  ```

  ```json Response theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "result": {
      "content": [
        {
          "type": "text",
          "text": "OK: token “Acme” created. Store it now: acme-example-token"
        }
      ],
      "structuredContent": {
        "token": {
          "id": "3c469e9d-6c58-45d3-8a43-f353d4f88e61",
          "label": "Acme",
          "createdAt": 1790069400000,
          "lastUsedAt": 1790069400000,
          "revokedAt": 1790069400000
        },
        "secret": "acme-example-token"
      }
    }
  }
  ```

  ```bash CLI theme={null}
  doers tokens create-api Acme
  ```
</CodeGroup>

## create\_referral\_invite

**Create an invite.**

Mints a code and returns it in `code`, **once**. Only a person who has had a free trial may grant one, and only up to the allowance; the code expires on its own.

|           |                                                                                 |
| --------- | ------------------------------------------------------------------------------- |
| Kind      | Write · no outside service                                                      |
| Auth      | Bearer token: a personal API token (`pc_…`) or an OAuth access token (`pcat_…`) |
| REST      | `POST https://api.doers.sh/v2/referrals`                                        |
| CLI       | `doers referrals create-referral-invite`                                        |
| Touches   | `creemCustomer`, `creemSubscription`, `invites`                                 |
| Operation | `createReferralInvite`                                                          |

### Input

This tool takes no arguments.

### Output

<Accordion title="Output fields">
  | Field               | Type           | Allowed values                | Description                                        |
  | ------------------- | -------------- | ----------------------------- | -------------------------------------------------- |
  | `invite`            | object         |                               |                                                    |
  | `invite.id`         | string         |                               |                                                    |
  | `invite.createdAt`  | number         |                               | Epoch milliseconds.                                |
  | `invite.expiresAt`  | number         |                               | Epoch milliseconds.                                |
  | `invite.redeemedAt` | number \| null |                               | `null` while the code is unredeemed.               |
  | `invite.status`     | string         | `open`, `redeemed`, `expired` | Derived from the two instants and the clock.       |
  | `code`              | string         |                               | The code to hand over. Shown once and never again. |
</Accordion>

### Example

<CodeGroup>
  ```json Request theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
      "name": "create_referral_invite",
      "arguments": {}
    }
  }
  ```

  ```json Response theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "result": {
      "content": [
        {
          "type": "text",
          "text": "OK: invite created. Hand this over: acme-example-token"
        }
      ],
      "structuredContent": {
        "invite": {
          "id": "5014f9af-3a68-4fdd-84a7-75c1c4c532ee",
          "createdAt": 1790069400000,
          "expiresAt": 1790069400000,
          "redeemedAt": 1790069400000,
          "status": "open"
        },
        "code": "acme-example-token"
      }
    }
  }
  ```

  ```bash CLI theme={null}
  doers referrals create-referral-invite
  ```
</CodeGroup>

## decide\_consent\_request

**Approve or refuse a consent request.**

Answers the request and returns where to send the browser next. The client is told either way: a refusal that simply stops leaves it waiting forever.

|           |                                                                                 |
| --------- | ------------------------------------------------------------------------------- |
| Kind      | Write · no outside service                                                      |
| Auth      | Bearer token: a personal API token (`pc_…`) or an OAuth access token (`pcat_…`) |
| REST      | `POST https://api.doers.sh/v2/connections/requests/{requestId}`                 |
| CLI       | `doers connections decide-consent-request`                                      |
| Touches   | no table directly                                                               |
| Operation | `decideConsentRequest`                                                          |

### Input

| Field              | Type    | Required | Default | Allowed values      | Description                                 |
| ------------------ | ------- | -------- | ------- | ------------------- | ------------------------------------------- |
| `requestId` (path) | string  | yes      |         | 1 to 128 characters | The consent request's opaque id.            |
| `approve`          | boolean | yes      |         |                     | `false` refuses, and says so to the client. |

### Output

<Accordion title="Output fields">
  | Field        | Type   | Allowed values | Description                                           |
  | ------------ | ------ | -------------- | ----------------------------------------------------- |
  | `redirectTo` | string | URL            | Where the browser continues. Already carries `state`. |
</Accordion>

### Example

<CodeGroup>
  ```json Request theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
      "name": "decide_consent_request",
      "arguments": {
        "requestId": "1f58b914-5b24-4108-87ac-38887338b3ea",
        "approve": true
      }
    }
  }
  ```

  ```json Response theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "result": {
      "content": [
        {
          "type": "text",
          "text": "OK: continue at https://acme.example/brief."
        }
      ],
      "structuredContent": {
        "redirectTo": "https://acme.example/brief"
      }
    }
  }
  ```

  ```bash CLI theme={null}
  doers connections decide-consent-request --request-id 1f58b914-5b24-4108-87ac-38887338b3ea --approve true
  ```
</CodeGroup>

## follow\_profile

**Follow someone.**

Only a public profile can be followed, and not your own. Following twice is a no-op.

|           |                                                                                 |
| --------- | ------------------------------------------------------------------------------- |
| Kind      | Write · no outside service                                                      |
| Auth      | Bearer token: a personal API token (`pc_…`) or an OAuth access token (`pcat_…`) |
| REST      | `POST https://api.doers.sh/v2/people/{username}/follow`                         |
| CLI       | `doers profiles follow`                                                         |
| Touches   | `follows`, `profiles`, `user`, `workSessions`                                   |
| Operation | `followProfile`                                                                 |

### Input

| Field             | Type   | Required | Default | Allowed values | Description                       |
| ----------------- | ------ | -------- | ------- | -------------- | --------------------------------- |
| `username` (path) | string | yes      |         |                | *No description in the registry.* |

### Output

<Accordion title="Output fields">
  | Field                                 | Type            | Allowed values        | Description                                    |
  | ------------------------------------- | --------------- | --------------------- | ---------------------------------------------- |
  | `profile`                             | object          |                       |                                                |
  | `profile.username`                    | string          |                       |                                                |
  | `profile.name`                        | string          |                       |                                                |
  | `profile.image`                       | string \| null  |                       |                                                |
  | `profile.foundingNumber`              | integer         | 1 to 9007199254740991 | Signup order: the first account is 1.          |
  | `profile.isFoundingMember`            | boolean \| null |                       | `null` while the founding cutoff is not named. |
  | `profile.followers`                   | integer         | 0 to 9007199254740991 |                                                |
  | `profile.following`                   | integer         | 0 to 9007199254740991 |                                                |
  | `profile.isFollowed`                  | boolean         |                       | Whether the caller follows this profile.       |
  | `profile.stats`                       | object \| null  |                       | `null` when the profile is not public.         |
  | `profile.stats.focusMinutesLast7Days` | integer         | 0 to 9007199254740991 |                                                |
  | `profile.stats.activeDaysLast28`      | integer         | 0 to 9007199254740991 |                                                |
  | `profile.stats.streakDays`            | integer         | 0 to 9007199254740991 |                                                |
</Accordion>

### Example

<CodeGroup>
  ```json Request theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
      "name": "follow_profile",
      "arguments": {
        "username": "ada"
      }
    }
  }
  ```

  ```json Response theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "result": {
      "content": [
        {
          "type": "text",
          "text": "OK: following @ada"
        }
      ],
      "structuredContent": {
        "profile": {
          "username": "ada",
          "name": "Acme",
          "image": "https://acme.example/ada.png",
          "foundingNumber": 3,
          "isFoundingMember": true,
          "followers": 3,
          "following": 3,
          "isFollowed": true,
          "stats": {
            "focusMinutesLast7Days": 30,
            "activeDaysLast28": 3,
            "streakDays": 3
          }
        }
      }
    }
  }
  ```

  ```bash CLI theme={null}
  doers profiles follow ada
  ```
</CodeGroup>

## grant\_team\_seat

**Seat someone on your team plan.**

Only while you hold a team plan with a seat to spare; never yourself. Seating someone twice is a no-op.

|           |                                                                                 |
| --------- | ------------------------------------------------------------------------------- |
| Kind      | Write · no outside service                                                      |
| Auth      | Bearer token: a personal API token (`pc_…`) or an OAuth access token (`pcat_…`) |
| REST      | `POST https://api.doers.sh/v2/billing/seats`                                    |
| CLI       | `doers billing grant-team-seat`                                                 |
| Touches   | `user`, `workspaceMembers`, `workspaces`                                        |
| Operation | `grantTeamSeat`                                                                 |

### Input

| Field      | Type   | Required | Default | Allowed values | Description                       |
| ---------- | ------ | -------- | ------- | -------------- | --------------------------------- |
| `username` | string | yes      |         |                | *No description in the registry.* |

### Output

<Accordion title="Output fields">
  | Field                        | Type           | Allowed values                             | Description                                  |
  | ---------------------------- | -------------- | ------------------------------------------ | -------------------------------------------- |
  | `entitlement`                | object         |                                            |                                              |
  | `entitlement.plan`           | string         | `free`, `pro`, `team`                      |                                              |
  | `entitlement.source`         | string \| null | `subscription`, `lifetime`, `seat`         | Where the plan comes from; `null` on free.   |
  | `entitlement.features`       | string\[]      | each: `username-reservation`, `team-seats` | The plan's features as of now, never frozen. |
  | `entitlement.seats`          | object \| null |                                            | `null` unless the account holds a team plan. |
  | `entitlement.seats.included` | integer        | 0 to 9007199254740991                      |                                              |
  | `entitlement.seats.used`     | integer        | 0 to 9007199254740991                      |                                              |
  | `entitlement.seats.members`  | string\[]      |                                            | The seated people, by handle.                |
</Accordion>

### Example

<CodeGroup>
  ```json Request theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
      "name": "grant_team_seat",
      "arguments": {
        "username": "ada"
      }
    }
  }
  ```

  ```json Response theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "result": {
      "content": [
        {
          "type": "text",
          "text": "OK: 3/3 seats"
        }
      ],
      "structuredContent": {
        "entitlement": {
          "plan": "free",
          "source": "subscription",
          "features": ["username-reservation"],
          "seats": {
            "included": 3,
            "used": 3,
            "members": ["Notes for the Acme launch."]
          }
        }
      }
    }
  }
  ```

  ```bash CLI theme={null}
  doers billing grant-team-seat ada
  ```
</CodeGroup>

## redeem\_referral\_invite

**Redeem an invite code.**

Records you as the person the code was for. A code redeems once, before it expires, and never by the person who made it.

|           |                                                                                 |
| --------- | ------------------------------------------------------------------------------- |
| Kind      | Write · no outside service                                                      |
| Auth      | Bearer token: a personal API token (`pc_…`) or an OAuth access token (`pcat_…`) |
| REST      | `POST https://api.doers.sh/v2/referrals/redeem`                                 |
| CLI       | `doers referrals redeem-referral-invite`                                        |
| Touches   | `creemCustomer`, `creemSubscription`, `invites`                                 |
| Operation | `redeemReferralInvite`                                                          |

### Input

| Field  | Type   | Required | Default | Allowed values     | Description                       |
| ------ | ------ | -------- | ------- | ------------------ | --------------------------------- |
| `code` | string | yes      |         | 1 to 32 characters | *No description in the registry.* |

### Output

<Accordion title="Output fields">
  | Field               | Type           | Allowed values                | Description                                  |
  | ------------------- | -------------- | ----------------------------- | -------------------------------------------- |
  | `invite`            | object         |                               |                                              |
  | `invite.id`         | string         |                               |                                              |
  | `invite.createdAt`  | number         |                               | Epoch milliseconds.                          |
  | `invite.expiresAt`  | number         |                               | Epoch milliseconds.                          |
  | `invite.redeemedAt` | number \| null |                               | `null` while the code is unredeemed.         |
  | `invite.status`     | string         | `open`, `redeemed`, `expired` | Derived from the two instants and the clock. |
</Accordion>

### Example

<CodeGroup>
  ```json Request theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
      "name": "redeem_referral_invite",
      "arguments": {
        "code": "acme-example-token"
      }
    }
  }
  ```

  ```json Response theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "result": {
      "content": [
        {
          "type": "text",
          "text": "OK: invite redeemed."
        }
      ],
      "structuredContent": {
        "invite": {
          "id": "5014f9af-3a68-4fdd-84a7-75c1c4c532ee",
          "createdAt": 1790069400000,
          "expiresAt": 1790069400000,
          "redeemedAt": 1790069400000,
          "status": "open"
        }
      }
    }
  }
  ```

  ```bash CLI theme={null}
  doers referrals redeem-referral-invite acme-example-token
  ```
</CodeGroup>

## revoke\_api\_token

**Revoke an API token.**

Takes effect on the next request that presents it. The row is kept rather than deleted, so a revoked token stays visible with the moment it was last used: which is what makes a leak legible after the fact.

|           |                                                                                 |
| --------- | ------------------------------------------------------------------------------- |
| Kind      | Write · destructive · idempotent · no outside service                           |
| Auth      | Bearer token: a personal API token (`pc_…`) or an OAuth access token (`pcat_…`) |
| REST      | `POST https://api.doers.sh/v2/tokens/{tokenId}/revoke`                          |
| CLI       | `doers tokens revoke-api`                                                       |
| Touches   | `apiTokens`                                                                     |
| Operation | `revokeApiToken`                                                                |

### Input

| Field            | Type   | Required | Default | Allowed values | Description          |
| ---------------- | ------ | -------- | ------- | -------------- | -------------------- |
| `tokenId` (path) | string | yes      |         | UUID           | Identifier of a row. |

### Output

<Accordion title="Output fields">
  | Field              | Type           | Allowed values | Description                            |
  | ------------------ | -------------- | -------------- | -------------------------------------- |
  | `token`            | object         |                |                                        |
  | `token.id`         | string         |                |                                        |
  | `token.label`      | string         |                |                                        |
  | `token.createdAt`  | number         |                | Epoch milliseconds.                    |
  | `token.lastUsedAt` | number \| null |                | `null` if it has never been presented. |
  | `token.revokedAt`  | number \| null |                |                                        |
</Accordion>

### Example

<CodeGroup>
  ```json Request theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
      "name": "revoke_api_token",
      "arguments": {
        "tokenId": "3c469e9d-6c58-45d3-8a43-f353d4f88e61"
      }
    }
  }
  ```

  ```json Response theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "result": {
      "content": [
        {
          "type": "text",
          "text": "OK: token “Acme” revoked."
        }
      ],
      "structuredContent": {
        "token": {
          "id": "3c469e9d-6c58-45d3-8a43-f353d4f88e61",
          "label": "Acme",
          "createdAt": 1790069400000,
          "lastUsedAt": 1790069400000,
          "revokedAt": 1790069400000
        }
      }
    }
  }
  ```

  ```bash CLI theme={null}
  doers tokens revoke-api 3c469e9d-6c58-45d3-8a43-f353d4f88e61
  ```
</CodeGroup>

## revoke\_connection

**Disconnect an application.**

Cuts the grant and deletes every token issued under it, so access stops on the next request rather than when the current token happens to expire.

|           |                                                                                 |
| --------- | ------------------------------------------------------------------------------- |
| Kind      | Write · destructive · idempotent · no outside service                           |
| Auth      | Bearer token: a personal API token (`pc_…`) or an OAuth access token (`pcat_…`) |
| REST      | `POST https://api.doers.sh/v2/connections/{connectionId}/revoke`                |
| CLI       | `doers connections revoke`                                                      |
| Touches   | no table directly                                                               |
| Operation | `revokeConnection`                                                              |

### Input

| Field                 | Type   | Required | Default | Allowed values | Description          |
| --------------------- | ------ | -------- | ------- | -------------- | -------------------- |
| `connectionId` (path) | string | yes      |         | UUID           | Identifier of a row. |

### Output

<Accordion title="Output fields">
  | Field     | Type    | Allowed values | Description |
  | --------- | ------- | -------------- | ----------- |
  | `revoked` | boolean |                |             |
</Accordion>

### Example

<CodeGroup>
  ```json Request theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
      "name": "revoke_connection",
      "arguments": {
        "connectionId": "b38d9d16-8c3a-4df1-86f4-f249b81adaef"
      }
    }
  }
  ```

  ```json Response theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "result": {
      "content": [
        {
          "type": "text",
          "text": "OK: application disconnected."
        }
      ],
      "structuredContent": {
        "revoked": true
      }
    }
  }
  ```

  ```bash CLI theme={null}
  doers connections revoke b38d9d16-8c3a-4df1-86f4-f249b81adaef
  ```
</CodeGroup>

## revoke\_team\_seat

**Take a seat back.**

The person keeps whatever they bought themselves. Not found when they had no seat.

|           |                                                                                 |
| --------- | ------------------------------------------------------------------------------- |
| Kind      | Write · destructive · idempotent · no outside service                           |
| Auth      | Bearer token: a personal API token (`pc_…`) or an OAuth access token (`pcat_…`) |
| REST      | `DELETE https://api.doers.sh/v2/billing/seats/{username}`                       |
| CLI       | `doers billing revoke-team-seat`                                                |
| Touches   | `user`, `workspaceMembers`, `workspaces`                                        |
| Operation | `revokeTeamSeat`                                                                |

### Input

| Field             | Type   | Required | Default | Allowed values | Description                       |
| ----------------- | ------ | -------- | ------- | -------------- | --------------------------------- |
| `username` (path) | string | yes      |         |                | *No description in the registry.* |

### Output

<Accordion title="Output fields">
  | Field                        | Type           | Allowed values                             | Description                                  |
  | ---------------------------- | -------------- | ------------------------------------------ | -------------------------------------------- |
  | `entitlement`                | object         |                                            |                                              |
  | `entitlement.plan`           | string         | `free`, `pro`, `team`                      |                                              |
  | `entitlement.source`         | string \| null | `subscription`, `lifetime`, `seat`         | Where the plan comes from; `null` on free.   |
  | `entitlement.features`       | string\[]      | each: `username-reservation`, `team-seats` | The plan's features as of now, never frozen. |
  | `entitlement.seats`          | object \| null |                                            | `null` unless the account holds a team plan. |
  | `entitlement.seats.included` | integer        | 0 to 9007199254740991                      |                                              |
  | `entitlement.seats.used`     | integer        | 0 to 9007199254740991                      |                                              |
  | `entitlement.seats.members`  | string\[]      |                                            | The seated people, by handle.                |
</Accordion>

### Example

<CodeGroup>
  ```json Request theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
      "name": "revoke_team_seat",
      "arguments": {
        "username": "ada"
      }
    }
  }
  ```

  ```json Response theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "result": {
      "content": [
        {
          "type": "text",
          "text": "OK: 3/3 seats"
        }
      ],
      "structuredContent": {
        "entitlement": {
          "plan": "free",
          "source": "subscription",
          "features": ["username-reservation"],
          "seats": {
            "included": 3,
            "used": 3,
            "members": ["Notes for the Acme launch."]
          }
        }
      }
    }
  }
  ```

  ```bash CLI theme={null}
  doers billing revoke-team-seat ada
  ```
</CodeGroup>

## set\_profile\_visibility

**Open or close your profile.**

Public lets anyone read your handle, your verified focus and your consistency: never a task, a note or a project. Private, the default, hides the profile from everyone but you; who follows you is kept either way. The leaderboards are a separate opt-in, off by default.

|           |                                                                                 |
| --------- | ------------------------------------------------------------------------------- |
| Kind      | Write · idempotent · no outside service                                         |
| Auth      | Bearer token: a personal API token (`pc_…`) or an OAuth access token (`pcat_…`) |
| REST      | `PUT https://api.doers.sh/v2/profiles/me/visibility`                            |
| CLI       | `doers profiles set-profile-visibility`                                         |
| Touches   | `follows`, `profiles`, `user`, `workSessions`                                   |
| Operation | `setProfileVisibility`                                                          |

### Input

| Field         | Type    | Required | Default | Allowed values      | Description                             |
| ------------- | ------- | -------- | ------- | ------------------- | --------------------------------------- |
| `visibility`  | string  | no       |         | `private`, `public` | Private until its owner says otherwise. |
| `leaderboard` | boolean | no       |         |                     | Opt into, or out of, the leaderboards.  |

### Output

<Accordion title="Output fields">
  | Field                      | Type            | Allowed values        | Description                                  |
  | -------------------------- | --------------- | --------------------- | -------------------------------------------- |
  | `profile`                  | object          |                       |                                              |
  | `profile.username`         | string \| null  |                       |                                              |
  | `profile.name`             | string          |                       |                                              |
  | `profile.image`            | string \| null  |                       |                                              |
  | `profile.visibility`       | string          | `private`, `public`   | Private until its owner says otherwise.      |
  | `profile.leaderboard`      | boolean         |                       | Opted into the leaderboards. Off by default. |
  | `profile.foundingNumber`   | integer         | 1 to 9007199254740991 |                                              |
  | `profile.isFoundingMember` | boolean \| null |                       |                                              |
  | `profile.followers`        | integer         | 0 to 9007199254740991 |                                              |
  | `profile.following`        | integer         | 0 to 9007199254740991 |                                              |
</Accordion>

### Example

<CodeGroup>
  ```json Request theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
      "name": "set_profile_visibility",
      "arguments": {
        "visibility": "private",
        "leaderboard": true
      }
    }
  }
  ```

  ```json Response theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "result": {
      "content": [
        {
          "type": "text",
          "text": "OK: profile is private, leaderboard on"
        }
      ],
      "structuredContent": {
        "profile": {
          "username": "ada",
          "name": "Acme",
          "image": "https://acme.example/ada.png",
          "visibility": "private",
          "leaderboard": true,
          "foundingNumber": 3,
          "isFoundingMember": true,
          "followers": 3,
          "following": 3
        }
      }
    }
  }
  ```

  ```bash CLI theme={null}
  doers profiles set-profile-visibility --visibility private --leaderboard true
  ```
</CodeGroup>

## unfollow\_profile

**Stop following someone.**

Works whatever their visibility now. Not found when you did not follow them.

|           |                                                                                 |
| --------- | ------------------------------------------------------------------------------- |
| Kind      | Write · destructive · idempotent · no outside service                           |
| Auth      | Bearer token: a personal API token (`pc_…`) or an OAuth access token (`pcat_…`) |
| REST      | `DELETE https://api.doers.sh/v2/people/{username}/follow`                       |
| CLI       | `doers profiles unfollow`                                                       |
| Touches   | `follows`, `profiles`, `user`, `workSessions`                                   |
| Operation | `unfollowProfile`                                                               |

### Input

| Field             | Type   | Required | Default | Allowed values | Description                       |
| ----------------- | ------ | -------- | ------- | -------------- | --------------------------------- |
| `username` (path) | string | yes      |         |                | *No description in the registry.* |

### Output

<Accordion title="Output fields">
  | Field | Type    | Allowed values | Description |
  | ----- | ------- | -------------- | ----------- |
  | `ok`  | boolean | `true`         |             |
</Accordion>

### Example

<CodeGroup>
  ```json Request theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
      "name": "unfollow_profile",
      "arguments": {
        "username": "ada"
      }
    }
  }
  ```

  ```json Response theme={null}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "result": {
      "content": [
        {
          "type": "text",
          "text": "OK: no longer following"
        }
      ],
      "structuredContent": {
        "ok": true
      }
    }
  }
  ```

  ```bash CLI theme={null}
  doers profiles unfollow ada
  ```
</CodeGroup>
