# Connect an MCP client to an organization (consent)

> The oauth_connections.create operation: POST /api/v1/oauth_connections in the REST API and the oauth_connections_create tool in the MCP server.

Lets an OAuth client that acts for you, such as an MCP client, work in one of your organizations with the
scopes you consent to. The consent screen calls it when you approve the client's authorization request;
`grantId` is that request's grant. The client then acts as you, with at most your own role there (re-checked on
every call), and never decides approval requests. Connecting again to the same organization replaces its scopes.
Partner apps are installed with `app_installations.create` instead.

## At a glance

- **REST:** `POST /api/v1/oauth_connections`
- **MCP tool:** `oauth_connections_create`
- **Operation ID:** `oauth_connections.create`
- **Scope:** Platform
- **Permission:** `account:write`
- **Risk tier:** `security`
- **Dry run:** Supported (send `Ownrecord-Dry-Run: true`)
- **Idempotency:** `Idempotency-Key` required
- **Modes:** Test and live
- **Authentication:** API key with the `account:write` scope
- **Since:** M10

## Request

### Body

A JSON object (`Content-Type: application/json`):

| Field      | Type                                                                                               | Required | Description |
| ---------- | -------------------------------------------------------------------------------------------------- | -------- | ----------- |
| `clientId` | `ocl_…` ID                                                                                         | Yes      |             |
| `grantId`  | `ogr_…` ID                                                                                         | Yes      |             |
| `orgId`    | `org_…` ID                                                                                         | Yes      |             |
| `scopes`   | array of one of 84 values, e.g. `org:read`, `org:write`, `org:admin` (all in the OpenAPI document) | Yes      |             |

## Response

`201 Created` with a JSON object:

| Field                | Type                                                                                               | Description |
| -------------------- | -------------------------------------------------------------------------------------------------- | ----------- |
| `id`                 | string                                                                                             |             |
| `object`             | `"oauth_connection"`                                                                               |             |
| `client`             | object                                                                                             |             |
| `client.id`          | `ocl_…` ID                                                                                         |             |
| `client.name`        | string                                                                                             |             |
| `client.publisher`   | string                                                                                             |             |
| `client.dynamic`     | boolean                                                                                            |             |
| `orgs`               | array of object                                                                                    |             |
| `orgs[].orgId`       | `org_…` ID                                                                                         |             |
| `orgs[].scopes`      | array of one of 84 values, e.g. `org:read`, `org:write`, `org:admin` (all in the OpenAPI document) |             |
| `orgs[].consentedAt` | string                                                                                             |             |
| `createdAt`          | string                                                                                             |             |
| `updatedAt`          | string                                                                                             |             |

## Examples

### Let Claude read filings and tasks

```http
POST /api/v1/oauth_connections
Authorization: Bearer or_test_…
Idempotency-Key: 3f1c9a52-7d0e-4b8f-9a61-0c2d5e8b7f14
Content-Type: application/json

{
  "clientId": "ocl_01m4ttwd3veh9apbewxheq5xhe",
  "grantId": "ogr_01m4ttwd3veh9apbewxheq5xhd",
  "orgId": "org_01m4ttwd3veh9apbewxheq5xh3",
  "scopes": [
    "filings:read",
    "tasks:read"
  ]
}
```

Response (`201`):

```json
{
  "id": "ogr_01m4ttwd3veh9apbewxheq5xhd",
  "object": "oauth_connection",
  "client": {
    "id": "ocl_01m4ttwd3veh9apbewxheq5xhe",
    "name": "Claude",
    "publisher": "Unverified (registered by the client itself)",
    "dynamic": true
  },
  "orgs": [
    {
      "orgId": "org_01m4ttwd3veh9apbewxheq5xh3",
      "scopes": ["filings:read", "tasks:read"],
      "consentedAt": "2026-10-25T09:00:00.000Z"
    }
  ],
  "createdAt": "2026-10-25T09:00:00.000Z",
  "updatedAt": "2026-10-25T09:00:00.000Z"
}
```

## Errors

| Code                                                                                           | HTTP status | When                                                                  | What to do                                                                                           |
| ---------------------------------------------------------------------------------------------- | ----------- | --------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------- |
| [`validation_failed`](https://ownrecord.io/docs/reference/errors.md#validation_failed)         | 400         | A scope isn't one the client may receive, or the client is an app.    | Fix the fields listed in `details.issues` and send the request again.                                |
| [`oauth_client_disabled`](https://ownrecord.io/docs/reference/errors.md#oauth_client_disabled) | 409         | The client is disabled.                                               | Register a new app, or create a new agent.                                                           |
| [`oauth_grant_mismatch`](https://ownrecord.io/docs/reference/errors.md#oauth_grant_mismatch)   | 400         | The grant isn't yours or isn't the client's.                          | Start the authorization again from the application.                                                  |
| [`resource_not_found`](https://ownrecord.io/docs/reference/errors.md#resource_not_found)       | 404         | The client doesn't exist, or you aren't a member of the organization. | Check the ID and that your credentials are scoped to the right organization, entity, brand and mode. |
| [`permission_denied`](https://ownrecord.io/docs/reference/errors.md#permission_denied)         | 403         | This isn't a signed-in person in the console.                         | Ask an organization owner or admin for a role or scope that allows this action.                      |

It can also return these [common errors](https://ownrecord.io/docs/reference.md#common-errors): [`api_version_unsupported`](https://ownrecord.io/docs/reference/errors.md#api_version_unsupported), [`invalid_json`](https://ownrecord.io/docs/reference/errors.md#invalid_json), [`unsupported_media_type`](https://ownrecord.io/docs/reference/errors.md#unsupported_media_type), [`authentication_required`](https://ownrecord.io/docs/reference/errors.md#authentication_required), [`api_key_invalid`](https://ownrecord.io/docs/reference/errors.md#api_key_invalid), [`idempotency_key_required`](https://ownrecord.io/docs/reference/errors.md#idempotency_key_required), [`idempotency_key_reused`](https://ownrecord.io/docs/reference/errors.md#idempotency_key_reused), [`idempotency_in_progress`](https://ownrecord.io/docs/reference/errors.md#idempotency_in_progress), [`rate_limited`](https://ownrecord.io/docs/reference/errors.md#rate_limited), [`internal_error`](https://ownrecord.io/docs/reference/errors.md#internal_error).
