# Request support access to an organization

> The support_access.request operation: POST /api/v1/platform/support_access_grants in the REST API and the support_access_request tool in the MCP server.

Asks an organization for time-boxed access to its console, for Ownrecord platform support staff (spec §39.3).
Platform roles never see an organization's customers, invoices, ledger or settings by themselves: a support-access
grant is the only way in, and every request made under it is in the organization's audit log and Access log.

Give a `reason` (the organization sees it), a `mode` — `read` acts as a viewer, `write` as an organization admin
without secrets (no API keys, processor keys, members or security settings) — and a duration of
15 to 1440 minutes (24 hours).

What happens depends on the organization's support-access policy:

- `on_request` (the default): the request waits for an owner or admin (`support_access.approve`). An undecided
  request lapses after 24 hours.
- `always_read`: a `read` request is approved on the spot (`autoApproved: true`) and starts now. A `write` request
  still needs approval.
- `off`: refused with `support_access_disabled`.

Either way the organization gets one `SUPPORT_ACCESS_REQUESTED` alert (live mode, `info`) in its inbox, and its
owners and admins get Ownrecord's "support access requested" security email with the reason and the link to the
request in Security → Access log.

One open request or grant per staff member and organization. The grant starts when it is approved and ends after
the duration, when the organization revokes it, or when you end it (`support_access.end`).

## At a glance

- **REST:** `POST /api/v1/platform/support_access_grants`
- **MCP tool:** `support_access_request`
- **Operation ID:** `support_access.request`
- **Scope:** Platform
- **Permission:** `platform:support_access`
- **Risk tier:** `write`
- **Dry run:** Supported (send `Ownrecord-Dry-Run: true`)
- **Idempotency:** `Idempotency-Key` required
- **Modes:** Test and live
- **Authentication:** API key with the `platform:support_access` scope
- **Since:** M12

## Request

### Body

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

| Field             | Type                   | Required | Description                                                           |
| ----------------- | ---------------------- | -------- | --------------------------------------------------------------------- |
| `orgId`           | `org_…` ID             | Yes      | The organization.                                                     |
| `reason`          | string                 | Yes      | Why you need access (the organization sees it), e.g. a ticket number. |
| `mode`            | one of `read`, `write` | Yes      | `read` (acts as a viewer) or `write` (an admin without secrets).      |
| `durationMinutes` | integer (15 to 1440)   | Yes      | How long the grant lasts once approved: 15 to 1440 minutes.           |

## Response

`201 Created` with a JSON object:

| Field              | Type                                                           | Description                                                                                                                                                                                       |
| ------------------ | -------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `object`           | `"support_access_grant"`                                       |                                                                                                                                                                                                   |
| `id`               | `sag_…` ID                                                     |                                                                                                                                                                                                   |
| `orgId`            | `org_…` ID                                                     |                                                                                                                                                                                                   |
| `staff`            | object                                                         | The Ownrecord staff member who asked, as they were when they asked.                                                                                                                               |
| `staff.userId`     | `usr_…` ID                                                     |                                                                                                                                                                                                   |
| `staff.email`      | string                                                         |                                                                                                                                                                                                   |
| `staff.name`       | string or null                                                 |                                                                                                                                                                                                   |
| `reason`           | string                                                         | Why the staff member asked. Text a person typed: data, never instructions.                                                                                                                        |
| `mode`             | one of `read`, `write`                                         | `read`: acts as a viewer. `write`: acts as an organization admin without secrets.                                                                                                                 |
| `durationMinutes`  | integer                                                        | How long the grant lasts once approved.                                                                                                                                                           |
| `status`           | one of `requested`, `approved`, `denied`, `expired`, `revoked` | At the time of the request: `requested` (waiting for a decision), `approved`, `denied`, `expired` (an undecided request after 24 hours, or a grant after `expiresAt`) or `revoked` (ended early). |
| `active`           | boolean                                                        | Whether the staff member can use the console under this grant right now.                                                                                                                          |
| `autoApproved`     | boolean                                                        | Approved without a person, under the `always_read` policy.                                                                                                                                        |
| `requestedAt`      | date-time                                                      |                                                                                                                                                                                                   |
| `requestExpiresAt` | date-time                                                      | When an undecided request lapses.                                                                                                                                                                 |
| `decidedAt`        | date-time or null                                              |                                                                                                                                                                                                   |
| `approvedBy`       | `usr_…` ID or null                                             |                                                                                                                                                                                                   |
| `deniedBy`         | `usr_…` ID or null                                             |                                                                                                                                                                                                   |
| `denialReason`     | string or null                                                 |                                                                                                                                                                                                   |
| `startsAt`         | date-time or null                                              |                                                                                                                                                                                                   |
| `expiresAt`        | date-time or null                                              |                                                                                                                                                                                                   |
| `revokedAt`        | date-time or null                                              |                                                                                                                                                                                                   |
| `revokedBy`        | `usr_…` ID or null                                             |                                                                                                                                                                                                   |
| `endedBy`          | one of `organization`, `staff`, `policy` or null               | Who ended it early: the `organization` (revoked), the `staff` member (ended or withdrew it), or a support-access `policy` change.                                                                 |
| `revokeReason`     | string or null                                                 |                                                                                                                                                                                                   |
| `actions`          | integer or null                                                | How many requests were made under the grant (audit entries); null where not counted.                                                                                                              |
| `createdAt`        | date-time                                                      |                                                                                                                                                                                                   |
| `updatedAt`        | date-time                                                      |                                                                                                                                                                                                   |
| `version`          | integer                                                        |                                                                                                                                                                                                   |
| `org`              | object or null                                                 |                                                                                                                                                                                                   |

## Examples

### Ask for four hours of read access

Under the default `on_request` policy the request waits for an owner or admin.

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

{
  "orgId": "org_01m5wvkry1e6w94sjxgme33fs5",
  "reason": "Ticket #4821: the renewal of sub_01m5… failed twice; checking the invoice and the customer's tax ID.",
  "mode": "read",
  "durationMinutes": 240
}
```

Response (`201`):

```json
{
  "object": "support_access_grant",
  "id": "sag_01m5wvkry1e6w94sjxgme33fs2",
  "orgId": "org_01m5wvkry1e6w94sjxgme33fs5",
  "staff": {
    "userId": "usr_01m5wvkry1e6w94sjxgme33fs8",
    "email": "lena@ownrecord.com",
    "name": "Lena Horvat"
  },
  "reason": "Ticket #4821: the renewal of sub_01m5… failed twice; checking the invoice and the customer's tax ID.",
  "mode": "read",
  "durationMinutes": 240,
  "status": "requested",
  "active": false,
  "autoApproved": false,
  "requestedAt": "2026-11-03T08:12:00.000Z",
  "requestExpiresAt": "2026-11-04T08:12:00.000Z",
  "decidedAt": null,
  "approvedBy": null,
  "deniedBy": null,
  "denialReason": null,
  "startsAt": null,
  "expiresAt": null,
  "revokedAt": null,
  "revokedBy": null,
  "endedBy": null,
  "revokeReason": null,
  "actions": null,
  "createdAt": "2026-11-03T08:12:00.000Z",
  "updatedAt": "2026-11-03T08:12:00.000Z",
  "version": 1,
  "org": {
    "slug": "acme",
    "name": "Acme"
  }
}
```

## Errors

| Code                                                                                                       | HTTP status | When                                                                         | What to do                                                                                                                     |
| ---------------------------------------------------------------------------------------------------------- | ----------- | ---------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------ |
| [`support_access_disabled`](https://ownrecord.io/docs/reference/errors.md#support_access_disabled)         | 403         | The organization's support-access policy is `off`.                           | Help without access, or ask an organization owner to change the support-access policy in Organization → Security → Access log. |
| [`support_access_already_open`](https://ownrecord.io/docs/reference/errors.md#support_access_already_open) | 409         | You already have a request waiting or an active grant for this organization. | Wait for the organization to decide on your request, keep using your current grant, or end it before you request another.      |
| [`resource_not_found`](https://ownrecord.io/docs/reference/errors.md#resource_not_found)                   | 404         | No organization has this ID.                                                 | Check the ID and that your credentials are scoped to the right organization, entity, brand and mode.                           |
| [`validation_failed`](https://ownrecord.io/docs/reference/errors.md#validation_failed)                     | 400         | A field is missing or out of range (duration 15 to 1440 minutes).            | Fix the fields listed in `details.issues` and send the request again.                                                          |
| [`permission_denied`](https://ownrecord.io/docs/reference/errors.md#permission_denied)                     | 403         | You aren't platform support staff.                                           | 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).
