## List Connected Apps

| Method | Path | Summary |
| --- | --- | --- |
| `GET` | `/v0/oauth-grants` | [List Connected Apps](/content/docs/reference/api/connected-apps#list-connected-apps/index.html) |
| `DELETE` | `/v0/oauth-grants/{grant_id}` | [Disconnect App](/content/docs/reference/api/connected-apps#disconnect-app/index.html) |

http

```
GET /v0/oauth-grants
```

Apps and MCP clients people in the organization connected with OAuth. Requires an organization-scoped credential with `api_key_read`; pod, inbox and sandbox credentials get `403`.

**Authentication:** `Authorization: Bearer <api key>` or the dashboard `mm_session` cookie. Permission: none beyond a valid key.

#### [Query parameters](/content/docs/reference/api/connected-apps#query-parameters/index.html)

Field|Description
---|---
`limit`|`integer` Maximum number of items to return. Default 50, maximum 500; larger values are capped.
`page_token`|`string` next_page_token from the previous page.
`ascending`|`boolean` Sort oldest first.

#### [Response](/content/docs/reference/api/connected-apps#response/index.html)

**200** A page of grants (`application/json`)

Field|Description
---|---
`count`|`integer` Required Number of items returned.
`limit`|`integer` Maximum number of items per page. Default 50, maximum 500; larger values are capped.
`next_page_token`|`string` Page token for pagination. Absent on the last page.
`oauth_grants`|[OAuthGrant[]](/content/docs/reference/api/objects#oauthgrant/index.html) Required Newest first unless ascending is set.

Each item of `oauth_grants` is a [OAuthGrant](/content/docs/reference/api/objects#oauthgrant/index.html):

Field|Description
---|---
`grant_id`|`string` Required ID of the grant (oag_...).
`client_id`|`string` Required
`client_name`|`string | null` Required Self-reported by the client at registration.
`client_uri`|`string | null` Required
`logo_uri`|`string | null` Required
`registration`|`"dynamic" | "metadata_document"` Required
`user_id`|`string` Required Who approved it.
`user_email`|`string | null` Required
`scopes`|`("inboxes.read" | "inboxes.write" | "messages.read" | "messages.send" | "messages.write" | "webhooks.read" | "webhooks.write" | "domains.read" | "domains.write" | "lists.read" | "lists.write" | "metrics.read" | "pods.read" | "pods.write" | "api_keys.read" | "api_keys.write")[]` Required
`resource`|`string` Required Audience of its access tokens.
`pod_id`|`string | null` Required Set when the grant is limited to one pod.
`inbox_id`|`string | null` Required Set when the grant is limited to one inbox.
`created_at`|`string (date-time)` Required
`last_used_at`|`string (date-time) | null` Required Last token refresh or API call (updated at most once a minute).
`expires_at`|`string (date-time)` Required When the current refresh token expires unless it is used (30 days after the last refresh).

#### [Errors](/content/docs/reference/api/connected-apps#errors/index.html)

| Status | Meaning |
| --- | --- |
| `400` | Invalid request: error.type is validation and error.param names the field. |
| `401` | Missing, invalid, expired or revoked credential. |
| `403` | The credential lacks the permission or scope for this request (error.type forbidden), or MachineMail suspended the organization or its sending (account_suspended: error.message says what still works; do not retry or re-register). |
| `500` | Unexpected server error. |

Error bodies use the [error envelope](/content/docs/reference/errors/index.html).

#### [Example](/content/docs/reference/api/connected-apps#example/index.html)

Request

```
curl "https://api.machinemail.dev/v0/oauth-grants" \
  -H "Authorization: Bearer $MACHINEMAIL_API_KEY"
```

Response 200

```
{
  "count": 1,
  "limit": 50,
  "next_page_token": "eyJvIjo1MH0",
  "oauth_grants": [\
    {\
      "grant_id": "string",\
      "client_id": "my-client-id",\
      "client_name": "string",\
      "client_uri": "https://example.com",\
      "logo_uri": "https://example.com",\
      "registration": "dynamic",\
      "user_id": "usr_01k6x3j0rw0000n8w4yc0g3q5s",\
      "user_email": "agent@machinemail.dev",\
      "scopes": ["inboxes.read"],\
      "resource": "string",\
      "pod_id": "pod_01k6x2m9qd0001b8j4mr0w3d5f",\
      "inbox_id": "agent@machinemail.dev",\
      "created_at": "2026-10-01T12:00:00.000Z",\
      "last_used_at": "2026-10-01T12:00:00.000Z",\
      "expires_at": "2026-10-01T12:00:00.000Z"\
    }\
  ]
}
```

## Disconnect App

http

```
DELETE /v0/oauth-grants/{grant_id}
```

Revokes the grant: its refresh token and every access token issued from it stop working immediately (`401` on `/mcp` and `/v0`). Returns the grant as it was. Requires an organization-scoped credential with `api_key_delete`.

**Authentication:** `Authorization: Bearer <api key>` or the dashboard `mm_session` cookie. Permission: none beyond a valid key.

#### [Path parameters](/content/docs/reference/api/connected-apps#path-parameters/index.html)

Field|Description
---|---
`grant_id`|`string` Required ID of the grant (oag_...).

#### [Response](/content/docs/reference/api/connected-apps#response-1/index.html)

**200** The revoked grant (`application/json`)

#### [Errors](/content/docs/reference/api/connected-apps#errors-1/index.html)

| Status | Meaning |
| --- | --- |
| `401` | Missing, invalid, expired or revoked credential. |
| `403` | The credential lacks the permission or scope for this request (error.type forbidden), or MachineMail suspended the organization or its sending (account_suspended: error.message says what still works; do not retry or re-register). |
| `404` | Not found. Also returned for resources outside the credential scope. |
| `500` | Unexpected server error. |

Error bodies use the [error envelope](/content/docs/reference/errors/index.html).

#### [Example](/content/docs/reference/api/connected-apps#example-1/index.html)

Request

```
curl -X DELETE "https://api.machinemail.dev/v0/oauth-grants/string" \
  -H "Authorization: Bearer $MACHINEMAIL_API_KEY"
```

Response 200

```
{
  "grant_id": "string",
  "client_id": "my-client-id",
  "client_name": "string",
  "client_uri": "https://example.com",
  "logo_uri": "https://example.com",
  "registration": "dynamic",
  "user_id": "usr_01k6x3j0rw0000n8w4yc0g3q5s",
  "user_email": "agent@machinemail.dev",
  "scopes": ["inboxes.read"],
  "resource": "string",
  "pod_id": "pod_01k6x2m9qd0001b8j4mr0w3d5f",
  "inbox_id": "agent@machinemail.dev",
  "created_at": "2026-10-01T12:00:00.000Z",
  "last_used_at": "2026-10-01T12:00:00.000Z",
  "expires_at": "2026-10-01T12:00:00.000Z"
}
```
