Skip to content

Approve an approval request

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

POST/api/v1/approvals/{id}/approve

Approves a pending approval request. Approvers are people in the console (never API keys, agents, apps or an OAuth or MCP client acting for a person) other than the requester (for an app: the person who installed it) who may run the operation themselves at its entity or brand and in its mode, and who signed in within the last 15 minutes. A request by an agent or app that a two-person rule covers needs two approvers (requiredApprovals: 2).

When the request has the approvals it needs, the operation runs as originally requested: the same input and Idempotency-Key, as the person, key, agent or app that asked, with their current access. The response is the request afterwards: executed (with resultRef), or stale when it can no longer run as requested (failure says why; the requester must ask again). A retryable failure leaves it approved with failure set: approve again to retry. Approving a request that is already approved or executed changes nothing.

At a glance

  • REST: POST /api/v1/approvals/{id}/approve
  • MCP tool: approvals_approve
  • Operation ID: approvals.approve
  • Scope: Organization
  • Permission: approvals: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 approvals:write scope
  • Fresh sign-in: In the console, a sign-in within the last 15 minutes
  • Since: M2

Request

Path parameters

FieldTypeDescription
idapr_… ID

Body

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

FieldTypeRequiredDescription
commentstringNo

Response

200 OK with a JSON object:

FieldTypeDescription
idapr_… ID
object"approval_request"
statusone of pending, approved, rejected, expired, executed, stale
operationIdstring
summarystring
orgIdorg_… ID
entityIdent_… ID or null
brandIdbrd_… ID or null
livemodeboolean
requestedByobject
requestedBy.typeone of user, api_key, agent, app, system, public, customer
requestedBy.idstring
requestedBy.viaone of console, api, mcp, assistant, portal, job or null
requestedBy.clientIdstring or null
requestedBy.onBehalfOfUserIdstring or null
requestedBy.appInstallationIdstring or null
amountmoney or null
inputany
dryRunobject
dryRun.outputany
dryRun.eventsarray of string
diffobject or null
requiredApprovalsinteger (1 to 2)
approvalsarray of object
approvals[].userIdusr_… ID
approvals[].atdate-time
approvals[].commentstring or null
rejectionobject or null
failureobject or null
resultRefstring or null
approveUrlstring
expiresAtdate-time
executedAtdate-time or null
createdAtdate-time
updatedAtdate-time

Examples

Approve a brand change

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

{
  "comment": "Checked with legal"
}

Response (200):

JSON
{
  "id": "apr_01m4ttwd3veh9apbewxheq5xh7",
  "object": "approval_request",
  "status": "executed",
  "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": [
    {
      "userId": "usr_01m4ttwd3veh9apbewxheq5xha",
      "at": "2026-10-13T14:30:00.000Z",
      "comment": "Checked with legal"
    }
  ],
  "rejection": null,
  "failure": null,
  "resultRef": "brd_01m4ttwd3veh9apbewxheq5xh5",
  "approveUrl": "https://ownrecord.io/console/acme/approvals/apr_01m4ttwd3veh9apbewxheq5xh7?mode=live",
  "expiresAt": "2026-10-16T12:00:00.000Z",
  "executedAt": "2026-10-13T14:30:00.000Z",
  "createdAt": "2026-10-13T12:00:00.000Z",
  "updatedAt": "2026-10-13T14:30:00.000Z"
}

Errors

CodeHTTP statusWhenWhat to do
resource_not_found404No 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.
self_approval_not_allowed403You made the request yourself.Ask another person who may run this operation to approve it.
approver_not_eligible403You 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_expired409Nobody approved the request within 72 hours.Send the request again with a new Idempotency-Key to create a new approval request. Requests expire after 72 hours.
approval_not_pending409The request was rejected or went stale.Read the request (GET /approvals/{id}) to see its status and outcome.
fresh_auth_required403You last signed in more than 15 minutes ago.Sign in again, then repeat the action within 15 minutes.
version_conflict409Someone decided at the same moment; retry.Fetch the object again and retry the change.
permission_denied403You 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: validation_failed, api_version_unsupported, invalid_json, unsupported_media_type, authentication_required, api_key_invalid, idempotency_key_required, idempotency_key_reused, idempotency_in_progress, rate_limited, internal_error.