> Source: https://wexa.ai/docs/governance/get-approval

# get-approval

Read one approval in this project: its status, who decided it, the reason and the choice they gave. Needs no grant. It returns the same shape as `GET /v1/approvals/{id}`.

**Read an approval**

**Wexa MCP server**

```bash
curl -sS -X POST https://fabric.wexa.ai/mcp/$FABRIC_PROJECT_ID \
  -H "authorization: Bearer $FABRIC_API_KEY" \
  -H "Mcp-Session-Id: $MCP_SESSION_ID" \
  -H "content-type: application/json" -H "accept: application/json" \
  -d '{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"get-approval","arguments":{"approval_id":"ar_6abbab02fb130d22ba652a81"}}}'
```

```json
{
  "content": [
    {
      "type": "text",
      "text": "{\"lifecycle_id\":\"qlc_000240\",\"result\":{\"id\":\"ar_6abbab02fb130d22ba652a81\",\"status\":\"approved\",\"what\":\"Pay supplier (Python wait)\",\"risk\":\"medium\",\"reference\":\"inbox-py-approve\",\"decided_by\":\"6abbaa9b4a684dc3e5a7bda0\",\"decision_reason\":\"Supplier verified in the console\"}}"
    }
  ],
  "isError": false
}
```

**REST API**

```bash
curl -sS https://fabric.wexa.ai/v1/get-approval \
  -H "authorization: Bearer $FABRIC_API_KEY" \
  -H "content-type: application/json" \
  -d '{"approval_id":"ar_6abbab02fb130d22ba652a81"}'
```

```json
{
  "lifecycle_id": "qlc_000240",
  "result": {
    "id": "ar_6abbab02fb130d22ba652a81",
    "status": "approved",
    "what": "Pay supplier (Python wait)",
    "risk": "medium",
    "reference": "inbox-py-approve",
    "decided_by": "6abbaa9b4a684dc3e5a7bda0",
    "decision_reason": "Supplier verified in the console"
  }
}
```

**TypeScript SDK**

```ts
import { Fabric } from '@wexa-fabric/sdk'

const fabric = new Fabric()
const result = await fabric.getApproval("ar_6abbab02fb130d22ba652a81")
```

```ts
// result is the payload itself, with no `.result` to read
{
  id: 'ar_6abbab02fb130d22ba652a81',
  status: 'approved',
  what: 'Pay supplier (Python wait)',
  risk: 'medium',
  reference: 'inbox-py-approve',
  decided_by: '6abbaa9b4a684dc3e5a7bda0',
  decision_reason: 'Supplier verified in the console'
}
```

**Python SDK**

```python
from wexa import Fabric

fabric = Fabric()
out = fabric.get_approval(approval_id="ar_6abbab02fb130d22ba652a81")
```

```python
# out is the result, already unwrapped
{
    "id": "ar_6abbab02fb130d22ba652a81",
    "status": "approved",
    "what": "Pay supplier (Python wait)",
    "risk": "medium",
    "reference": "inbox-py-approve",
    "decided_by": "6abbaa9b4a684dc3e5a7bda0",
    "decision_reason": "Supplier verified in the console"
}
```

## Parameters

| Parameter | Type | Required | Notes |
| --- | --- | --- | --- |
| `approval_id` | string | Required | Approval id, as returned by `request-approval` (`ar_...`). An approval in another project answers not found, the same as an id that does not exist. |

**Show full response**

A real response, captured from a live call to `get-approval`:

**Result of get-approval**

**REST API**

```json
{
  "lifecycle_id": "qlc_000240",
  "result": {
    "args": null,
    "created_at": "2026-09-29T12:11:46.83Z",
    "decided_at": "2026-09-29T12:14:38.712Z",
    "decided_by": "6abbaa9b4a684dc3e5a7bda0",
    "decision_reason": "Supplier verified in the console",
    "expires_at": "2026-10-01T12:11:46.83Z",
    "hard_expires_at": "2026-10-03T12:11:46.83Z",
    "id": "ar_6abbab02fb130d22ba652a81",
    "lifecycle_id": "",
    "reference": "inbox-py-approve",
    "requested_by": "6abbaa9b4a684dc3e5a7bda0",
    "risk": "medium",
    "scope": {
      "auth_kind": "",
      "grants": null,
      "org_id": "6abbaa9b4a684dc3e5a7bda1",
      "project_id": "6abbaa9b4a684dc3e5a7bdb1",
      "role": "",
      "user_id": "6abbaa9b4a684dc3e5a7bda0"
    },
    "status": "approved",
    "tool": "",
    "type": "app_request",
    "what": "Pay supplier (Python wait)",
    "why": "Decided in the Fabric console Inbox"
  }
}
```

**Wexa MCP server**

```json
{
  "content": [
    {
      "type": "text",
      "text": "{\"lifecycle_id\":\"qlc_000241\",\"result\":{\"args\":null,\"created_at\":\"2026-09-29T12:11:46.83Z\",\"decided_at\":\"2026-09-29T12:14:38.712Z\",\"decided_by\":\"6abbaa9b4a684dc3e5a7bda0\",\"decision_reason\":\"Supplier verified in the console\",\"expires_at\":\"2026-10-01T12:11:46.83Z\",\"hard_expires_at\":\"2026-10-03T12:11:46.83Z\",\"id\":\"ar_6abbab02fb130d22ba652a81\",\"lifecycle_id\":\"\",\"reference\":\"inbox-py-approve\",\"requested_by\":\"6abbaa9b4a684dc3e5a7bda0\",\"risk\":\"medium\",\"scope\":{\"auth_kind\":\"\",\"grants\":null,\"org_id\":\"6abbaa9b4a684dc3e5a7bda1\",\"project_id\":\"6abbaa9b4a684dc3e5a7bdb1\",\"role\":\"\",\"user_id\":\"6abbaa9b4a684dc3e5a7bda0\"},\"status\":\"approved\",\"tool\":\"\",\"type\":\"app_request\",\"what\":\"Pay supplier (Python wait)\",\"why\":\"Decided in the Fabric console Inbox\"}}"
    }
  ],
  "isError": false
}
```

**TypeScript SDK**

```ts
// the object you get back IS the result — there is no `.result` to read
{
  args: null,
  choice: 'send',
  choices: ['send', 'hold'],
  created_at: '2026-09-29T12:11:46.826Z',
  decided_at: '2026-09-29T12:14:39.923Z',
  decided_by: '6abbaa9b4a684dc3e5a7bda0',
  expires_at: '2026-09-30T12:11:46.826Z',
  hard_expires_at: '2026-10-01T12:11:46.826Z',
  id: 'ar_6abbab02fb130d22ba652a7f',
  lifecycle_id: '',
  reference: 'inbox-js-1',
  requested_by: '6abbaa9b4a684dc3e5a7bda0',
  risk: 'high',
  scope: {
    auth_kind: '',
    grants: null,
    org_id: '6abbaa9b4a684dc3e5a7bda1',
    project_id: '6abbaa9b4a684dc3e5a7bdb1',
    role: '',
    user_id: '6abbaa9b4a684dc3e5a7bda0'
  },
  status: 'approved',
  tool: '',
  type: 'app_request',
  what: 'Send campaign C-99 (JS wait)',
  why: 'Decided in the Fabric console Inbox'
}

// The TS SDK names these camelCase — lifecycleId, traceId — where Python uses
// lifecycle_id and trace_id. Both are non-enumerable: readable, but omitted by
// Object.keys() and JSON.stringify(). `result.lifecycleId` here is undefined.
result.lifecycleId // 'qlc_000242'
```

**Python SDK**

```python
# a dict subclass; `result` is already unwrapped
{
 "args": None,
 "created_at": "2026-09-29T12:11:46.824Z",
 "decided_at": "2026-09-29T12:14:40.99Z",
 "decided_by": "6abbaa9b4a684dc3e5a7bda0",
 "decision_reason": "Legal hold on this customer",
 "expires_at": "2026-10-01T12:11:46.824Z",
 "hard_expires_at": "2026-10-03T12:11:46.824Z",
 "id": "ar_6abbab02fb130d22ba652a7e",
 "lifecycle_id": "",
 "reference": "inbox-py-reject",
 "requested_by": "6abbaa9b4a684dc3e5a7bda0",
 "risk": "medium",
 "scope": {
  "auth_kind": "",
  "grants": None,
  "org_id": "6abbaa9b4a684dc3e5a7bda1",
  "project_id": "6abbaa9b4a684dc3e5a7bdb1",
  "role": "",
  "user_id": "6abbaa9b4a684dc3e5a7bda0"
 },
 "status": "rejected",
 "tool": "",
 "type": "app_request",
 "what": "Delete customer data (Python wait)",
 "why": "Decided in the Fabric console Inbox"
}

out.lifecycle_id  # 'qlc_000243' — an attribute, not a key
```

**More details**

For an approval opened with [`request-approval`](/docs/governance/request-approval), `reference` is the reference you passed. For how approvals are decided and resumed, see [policy and approvals](/docs/governance/policy-and-approvals).

- `pending`: Waiting for a decision. Final: no.
- `overdue`: Past its deadline (`expires_at`) and still waiting. It can still be decided. Final for an SDK wait.
- `approved`: A person approved it. `decided_by`, `decided_at`, and `choice` when one was picked. Final.
- `rejected`: A person rejected it. `decision_reason` says why. Final.
- `expired`: Past `hard_expires_at` with no decision. It can no longer be decided. Final.

An SDK that waits for a decision stops at `overdue`, the same as the wait on a held tool call. To keep waiting for an overdue approval, call `get-approval` again later.

- `id` (string): The approval id.
- `type` (string): `app_request` for an approval opened with `request-approval`.
- `status` (string): One of the statuses above.
- `what`, `why` (string): The title and reason the request was opened with.
- `risk` (string): `low`, `medium` or `high`.
- `payload` (object): The details sent with the request, when there were any.
- `choices`, `choice` (array, string): The options offered, and the one the approver picked.
- `requested_by` (string): The user the request was made as.
- `decided_by`, `decided_at` (string): Who decided it, and when.
- `decision_reason` (string): The reason the approver gave. Always present on a rejection.
- `consumed` (boolean): Present and `true` once a held tool call has used its approval.
- `created_at`, `expires_at`, `hard_expires_at` (string): When it was opened, its deadline, and when it expires.
- `reference` (string): The reference passed to `request-approval`.

Not marked consequential: it only reads, is audited lightly and is never held for approval.

Every tool call works the same way: [How every tool call works](/docs/sdks-and-apis/how-every-tool-call-works).
