# OAuth consent API reference

> The consent operations behind MCP sign-in at Fax for Agents. Read a pending authorization, allow or deny it, list the connected apps and revoke one.

Page: https://faxforagents.com/docs/api/reference/oauth/
Last changed: 2026-11-13

Updated Nov 13, 2026

5 operations of the Fax for Agents API, from the OpenAPI document version 1.20.0, snapshot of 2026-11-13. The base URL is `https://api.faxforagents.com/v1`. This is one group of the [full reference](https://faxforagents.com/docs/api/reference/).

- Allowing an authorization mints the authorization code and returns where the browser goes next.
- Denying an authorization sends the app an access_denied answer.
- An OAuth access token works on the MCP server only, and the REST API answers it with 401.

## Operations

- `GET /v1/oauth/authorizations/{authorization_id}` The pending consent behind a consent URL: the app, the scopes and your organizations
- `POST /v1/oauth/authorizations/{authorization_id}/approve` Allow: mint the authorization code and return where the browser goes next
- `POST /v1/oauth/authorizations/{authorization_id}/deny` Deny: send the app an access_denied answer
- `GET /v1/oauth/grants` Your connected apps in this organization
- `DELETE /v1/oauth/grants/{grant_id}` Revoke a connected app

## What is this group for?

For the consent screen. When an AI client connects to the MCP server with OAuth, it sends the person to a consent URL. The dashboard reads the pending authorization from this group, shows it, and posts the person's answer. The token endpoints of the OAuth flow are outside `/v1` and are not part of this document.

## What does the consent screen read?

`GET /v1/oauth/authorizations/{authorization_id}` returns the pending consent. `client` is the app that asks, and `redirect_host` is the host it will return to. The answer also has the `scopes_requested`, the person's organizations and the default environment. It expires at `expires_at`. The call takes a signed-in session.

## How is the answer given?

`POST /v1/oauth/authorizations/{authorization_id}/approve` allows. The body names the `org_id` and the `environment` the app is connected to. It mints the authorization code and returns `redirect_to`, the address the browser opens next. `auto_send` is the consent screen's checkbox, for owners only.

`POST /v1/oauth/authorizations/{authorization_id}/deny` denies. The app gets an `access_denied` answer through the same `redirect_to`.

## How are connected apps listed and revoked?

`GET /v1/oauth/grants` lists the connected apps of the organization. `DELETE /v1/oauth/grants/{grant_id}` revokes one, and that connection's tokens stop working. Both need `key:admin`, the scope that also guards API keys.

Revoking an app does not cancel a fax that is already queued. The [OAuth guide](https://faxforagents.com/docs/mcp/) walks through the screen a person sees.

## Does an OAuth token work on this API?

No. An access token from the MCP sign-in works on the MCP server only. The REST API answers it with 401 `invalid_token`. A script that calls REST uses an API key from the [identity group](https://faxforagents.com/docs/api/reference/identity/).

## Each operation in detail

### GET `/v1/oauth/authorizations/{authorization_id}`

The pending consent behind a consent URL: the app, the scopes and your organizations

Credential: a signed-in session.

#### Parameters

GET /v1/oauth/authorizations/{authorization_id} parameters

| Name | In | Type | Required | Notes |
| --- | --- | --- | --- | --- |
| `authorization_id` | path | string | yes |  |

#### Responses

GET /v1/oauth/authorizations/{authorization_id} responses

| Status | Meaning |
| --- | --- |
| `200` | Successful Response |
| `401` | No credential, or one that was not accepted: invalid_token for an API key, unauthenticated where a signed-in session is needed. error.details.reason says why a key was refused. |
| `404` | not_found: no such resource for this credential. A resource of another organization answers the same. |
| `422` | A field failed validation: invalid_request, with one entry per field in error.details, or a code that names the rule. |
| `429` | rate_limited. Retry-After and the RateLimit-* headers say when to try again. |

#### Response fields

GET /v1/oauth/authorizations/{authorization_id} response fields

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `client` | object OAuthConsentClient | yes |  |
| `default_environment` | string (live, test) | yes |  |
| `expires_at` | string | yes |  |
| `id` | string | yes |  |
| `organizations` | array of object OAuthConsentOrganization | yes |  |
| `redirect_host` | string | yes |  |
| `scopes_requested` | array of string | yes |  |

#### Example

```
`curl https://api.faxforagents.com/v1/oauth/authorizations/AUTHORIZATION_ID`
```

### POST `/v1/oauth/authorizations/{authorization_id}/approve`

Allow: mint the authorization code and return where the browser goes next

Credential: a signed-in session.

#### Parameters

POST /v1/oauth/authorizations/{authorization_id}/approve parameters

| Name | In | Type | Required | Notes |
| --- | --- | --- | --- | --- |
| `authorization_id` | path | string | yes |  |
| `Idempotency-Key` | header | string | no | Replay the first successful response for the same request within 24 hours. Reusing the idempotency header with a different request returns 409 idempotency_key_conflict. Responses include Idempotent-Replayed: true on replay. |

#### Request body application/json, required

POST /v1/oauth/authorizations/{authorization_id}/approve request body

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `auto_send` | boolean or null | no | The consent screen's checkbox, owners only: false turns the organization's auto-send setting off for this environment, true turns it on with its current limits. Omitted leaves it. |
| `environment` | string (live, test) | no |  |
| `org_id` | string | yes |  |

#### Responses

POST /v1/oauth/authorizations/{authorization_id}/approve responses

| Status | Meaning |
| --- | --- |
| `200` | Successful Response |
| `401` | No credential, or one that was not accepted: invalid_token for an API key, unauthenticated where a signed-in session is needed. error.details.reason says why a key was refused. |
| `403` | The credential is valid and is not allowed to do this. scope_missing puts the scope in error.details.scope. Other codes are agent_forbidden and approval_required. A session can also meet csrf_invalid and reauth_required. |
| `404` | not_found: no such resource for this credential. A resource of another organization answers the same. |
| `409` | The resource is in a state that refuses the call, or the Idempotency-Key was used with a different request (idempotency_key_conflict). error.code names the state. |
| `422` | A field failed validation: invalid_request, with one entry per field in error.details, or a code that names the rule. |
| `429` | rate_limited. Retry-After and the RateLimit-* headers say when to try again. |

#### Response fields

POST /v1/oauth/authorizations/{authorization_id}/approve response fields

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `redirect_to` | string | yes | Where the browser goes next: the client's registered redirect URI. |

#### Example

```
`curl https://api.faxforagents.com/v1/oauth/authorizations/AUTHORIZATION_ID/approve \ -X POST \ -H "Content-Type: application/json" \ -d '{"org_id":"org_example"}'`
```

### POST `/v1/oauth/authorizations/{authorization_id}/deny`

Deny: send the app an access_denied answer

Credential: a signed-in session.

#### Parameters

POST /v1/oauth/authorizations/{authorization_id}/deny parameters

| Name | In | Type | Required | Notes |
| --- | --- | --- | --- | --- |
| `authorization_id` | path | string | yes |  |
| `Idempotency-Key` | header | string | no | Replay the first successful response for the same request within 24 hours. Reusing the idempotency header with a different request returns 409 idempotency_key_conflict. Responses include Idempotent-Replayed: true on replay. |

#### Responses

POST /v1/oauth/authorizations/{authorization_id}/deny responses

| Status | Meaning |
| --- | --- |
| `200` | Successful Response |
| `401` | No credential, or one that was not accepted: invalid_token for an API key, unauthenticated where a signed-in session is needed. error.details.reason says why a key was refused. |
| `403` | The credential is valid and is not allowed to do this. scope_missing puts the scope in error.details.scope. Other codes are agent_forbidden and approval_required. A session can also meet csrf_invalid and reauth_required. |
| `404` | not_found: no such resource for this credential. A resource of another organization answers the same. |
| `409` | The resource is in a state that refuses the call, or the Idempotency-Key was used with a different request (idempotency_key_conflict). error.code names the state. |
| `422` | A field failed validation: invalid_request, with one entry per field in error.details, or a code that names the rule. |
| `429` | rate_limited. Retry-After and the RateLimit-* headers say when to try again. |

#### Response fields

POST /v1/oauth/authorizations/{authorization_id}/deny response fields

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `redirect_to` | string | yes | Where the browser goes next: the client's registered redirect URI. |

#### Example

```
`curl https://api.faxforagents.com/v1/oauth/authorizations/AUTHORIZATION_ID/deny \ -X POST`
```

### GET `/v1/oauth/grants`

Your connected apps in this organization

Credential: an API key or a signed-in session. Scope: `key:admin`.

#### Parameters

GET /v1/oauth/grants parameters

| Name | In | Type | Required | Notes |
| --- | --- | --- | --- | --- |
| `cursor` | query | string or null | no |  |
| `limit` | query | integer | no | Default `100` . |

#### Responses

GET /v1/oauth/grants responses

| Status | Meaning |
| --- | --- |
| `200` | Successful Response |
| `401` | No credential, or one that was not accepted: invalid_token for an API key, unauthenticated where a signed-in session is needed. error.details.reason says why a key was refused. |
| `403` | The credential is valid and is not allowed to do this. scope_missing puts the scope in error.details.scope. Other codes are agent_forbidden and approval_required. A session can also meet csrf_invalid and reauth_required. |
| `404` | not_found: no such resource for this credential. A resource of another organization answers the same. |
| `422` | A field failed validation: invalid_request, with one entry per field in error.details, or a code that names the rule. |
| `429` | rate_limited. Retry-After and the RateLimit-* headers say when to try again. |

#### Response fields

GET /v1/oauth/grants response fields

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `items` | array of object Grant | yes |  |
| `next_cursor` | string or null | no |  |

#### Example

```
`curl https://api.faxforagents.com/v1/oauth/grants \ -H "Authorization: Bearer ffa_test_..."`
```

### DELETE `/v1/oauth/grants/{grant_id}`

Revoke a connected app

Credential: an API key or a signed-in session. Scope: `key:admin`.

#### Parameters

DELETE /v1/oauth/grants/{grant_id} parameters

| Name | In | Type | Required | Notes |
| --- | --- | --- | --- | --- |
| `grant_id` | path | string | yes |  |
| `Idempotency-Key` | header | string | no | Replay the first successful response for the same request within 24 hours. Reusing the idempotency header with a different request returns 409 idempotency_key_conflict. Responses include Idempotent-Replayed: true on replay. |

#### Responses

DELETE /v1/oauth/grants/{grant_id} responses

| Status | Meaning |
| --- | --- |
| `204` | Successful Response |
| `401` | No credential, or one that was not accepted: invalid_token for an API key, unauthenticated where a signed-in session is needed. error.details.reason says why a key was refused. |
| `403` | The credential is valid and is not allowed to do this. scope_missing puts the scope in error.details.scope. Other codes are agent_forbidden and approval_required. A session can also meet csrf_invalid and reauth_required. |
| `404` | not_found: no such resource for this credential. A resource of another organization answers the same. |
| `409` | The resource is in a state that refuses the call, or the Idempotency-Key was used with a different request (idempotency_key_conflict). error.code names the state. |
| `422` | A field failed validation: invalid_request, with one entry per field in error.details, or a code that names the rule. |
| `429` | rate_limited. Retry-After and the RateLimit-* headers say when to try again. |

#### Example

```
`curl https://api.faxforagents.com/v1/oauth/grants/GRANT_ID \ -X DELETE \ -H "Authorization: Bearer ffa_test_..."`
```
