# Reject an approval request

> The approvals.reject operation: POST /api/v1/approvals/{id}/reject in the REST API and the approvals_reject tool in the MCP server.

Rejects a pending approval request with a reason. The operation never runs; the requester sees the reason
and must send a new request (with a new Idempotency-Key) to try again. The same people who may approve a
request may reject it, and the requester may reject (withdraw) their own request. Emits `approval.resolved`.

## At a glance

- **REST:** `POST /api/v1/approvals/{id}/reject`
- **MCP tool:** `approvals_reject`
- **Operation ID:** `approvals.reject`
- **Scope:** Organization
- **Permission:** `approvals:write`
- **Risk tier:** `write`
- **Dry run:** Supported (send `Ownrecord-Dry-Run: true`)
- **Idempotency:** `Idempotency-Key` required
- **Modes:** Test and live
- **Authentication:** API key with the `approvals:write` scope
- **Since:** M2

## Request

### Path parameters

| Field | Type       | Description |
| ----- | ---------- | ----------- |
| `id`  | `apr_…` ID |             |

### Body

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

| Field    | Type   | Required | Description |
| -------- | ------ | -------- | ----------- |
| `reason` | string | Yes      |             |

## Response

`200 OK` with a JSON object:

| Field                           | Type                                                                     | Description |
| ------------------------------- | ------------------------------------------------------------------------ | ----------- |
| `id`                            | `apr_…` ID                                                               |             |
| `object`                        | `"approval_request"`                                                     |             |
| `status`                        | one of `pending`, `approved`, `rejected`, `expired`, `executed`, `stale` |             |
| `operationId`                   | string                                                                   |             |
| `summary`                       | string                                                                   |             |
| `orgId`                         | `org_…` ID                                                               |             |
| `entityId`                      | `ent_…` ID or null                                                       |             |
| `brandId`                       | `brd_…` ID or null                                                       |             |
| `livemode`                      | boolean                                                                  |             |
| `requestedBy`                   | object                                                                   |             |
| `requestedBy.type`              | one of `user`, `api_key`, `agent`, `app`, `system`, `public`, `customer` |             |
| `requestedBy.id`                | string                                                                   |             |
| `requestedBy.via`               | one of `console`, `api`, `mcp`, `assistant`, `portal`, `job` or null     |             |
| `requestedBy.clientId`          | string or null                                                           |             |
| `requestedBy.onBehalfOfUserId`  | string or null                                                           |             |
| `requestedBy.appInstallationId` | string or null                                                           |             |
| `amount`                        | money or null                                                            |             |
| `input`                         | any                                                                      |             |
| `dryRun`                        | object                                                                   |             |
| `dryRun.output`                 | any                                                                      |             |
| `dryRun.events`                 | array of string                                                          |             |
| `diff`                          | object or null                                                           |             |
| `requiredApprovals`             | integer (1 to 2)                                                         |             |
| `approvals`                     | array of object                                                          |             |
| `approvals[].userId`            | `usr_…` ID                                                               |             |
| `approvals[].at`                | date-time                                                                |             |
| `approvals[].comment`           | string or null                                                           |             |
| `rejection`                     | object or null                                                           |             |
| `failure`                       | object or null                                                           |             |
| `resultRef`                     | string or null                                                           |             |
| `approveUrl`                    | string                                                                   |             |
| `expiresAt`                     | date-time                                                                |             |
| `executedAt`                    | date-time or null                                                        |             |
| `createdAt`                     | date-time                                                                |             |
| `updatedAt`                     | date-time                                                                |             |

## Examples

### Reject a brand change

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

{
  "reason": "The descriptor must match the registered name."
}
```

Response (`200`):

```json
{
  "id": "apr_01m4ttwd3veh9apbewxheq5xh7",
  "object": "approval_request",
  "status": "rejected",
  "operationId": "brands.update",
  "summary": "Update a brand",
  "orgId": "org_01m4ttwd3veh9apbewxheq5xh3",
  "entityId": "ent_01m4ttwd3veh9apbewxheq5xh4",
  "brandId": "brd_01m4ttwd3veh9apbewxheq5xh5",
  "livemode": true,
  "requestedBy": {
    "type": "user",
    "id": "usr_01m4ttwd3veh9apbewxheq5xh6",
    "via": "console",
    "clientId": null,
    "onBehalfOfUserId": null,
    "appInstallationId": null
  },
  "amount": null,
  "input": {
    "id": "brd_01m4ttwd3veh9apbewxheq5xh5",
    "statementDescriptor": "ACME APP"
  },
  "dryRun": {
    "output": {
      "id": "brd_01m4ttwd3veh9apbewxheq5xh5",
      "statementDescriptor": "ACME APP"
    },
    "events": ["brand.updated"]
  },
  "diff": {
    "before": {
      "statementDescriptor": "ACME"
    },
    "after": {
      "statementDescriptor": "ACME APP"
    }
  },
  "requiredApprovals": 1,
  "approvals": [],
  "rejection": {
    "userId": "usr_01m4ttwd3veh9apbewxheq5xha",
    "at": "2026-10-13T14:30:00.000Z",
    "reason": "The descriptor must match the registered name."
  },
  "failure": null,
  "resultRef": null,
  "approveUrl": "https://ownrecord.io/console/acme/approvals/apr_01m4ttwd3veh9apbewxheq5xh7?mode=live",
  "expiresAt": "2026-10-16T12:00:00.000Z",
  "executedAt": null,
  "createdAt": "2026-10-13T12:00:00.000Z",
  "updatedAt": "2026-10-13T14:30:00.000Z"
}
```

## Errors

| Code                                                                                           | HTTP status | When                                                                                                                                                    | What to do                                                                                                                                                                                                    |
| ---------------------------------------------------------------------------------------------- | ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [`resource_not_found`](https://ownrecord.io/docs/reference/errors.md#resource_not_found)       | 404         | No approval request with this ID exists in this organization and mode.                                                                                  | Check the ID and that your credentials are scoped to the right organization, entity, brand and mode.                                                                                                          |
| [`approver_not_eligible`](https://ownrecord.io/docs/reference/errors.md#approver_not_eligible) | 403         | You can't run the operation yourself at its entity or brand in this mode, you are an API key, agent or app, or you call through an OAuth or MCP client. | Approval requests are decided by people in the Ownrecord console (not API keys, agents, apps or MCP clients) who may run the operation themselves, at its entity or brand and in its mode. Ask such a person. |
| [`approval_expired`](https://ownrecord.io/docs/reference/errors.md#approval_expired)           | 409         | The request expired before anyone decided.                                                                                                              | Send the request again with a new Idempotency-Key to create a new approval request. Requests expire after 72 hours.                                                                                           |
| [`approval_not_pending`](https://ownrecord.io/docs/reference/errors.md#approval_not_pending)   | 409         | The request was already approved, rejected or run.                                                                                                      | Read the request (`GET /approvals/{id}`) to see its status and outcome.                                                                                                                                       |
| [`version_conflict`](https://ownrecord.io/docs/reference/errors.md#version_conflict)           | 409         | Someone decided at the same moment; retry.                                                                                                              | Fetch the object again and retry the change.                                                                                                                                                                  |
| [`permission_denied`](https://ownrecord.io/docs/reference/errors.md#permission_denied)         | 403         | You can't decide on approval requests here.                                                                                                             | 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): [`validation_failed`](https://ownrecord.io/docs/reference/errors.md#validation_failed), [`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).
