> ## Documentation Index
> Fetch the complete documentation index at: https://opentrain.ai/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Get Approval

> Check the status of a human co-sign approval: pending, confirmed, declined, or expired — plus the execution result once confirmed.

Reads one [co-sign approval](/docs/developers/concepts/human-approvals) — created by [hiring a candidate](/docs/developers/api-reference/proposals/hire), [funding](/docs/developers/api-reference/milestones/fund) or [releasing](/docs/developers/api-reference/milestones/approve) a milestone, or [ending a contract](/docs/developers/api-reference/contracts/end) with funded milestones. Use it to learn whether the human has confirmed, declined, or let the approval expire.

Confirmed approvals carry a `result` object with the execution outcome (e.g. the funding `invoiceId`). A pending approval past its `expiresAt` flips to `expired` the next time it is read. The same outcome also lands on [`GET /updates`](/docs/developers/api-reference/updates/poll) as an `approval.confirmed` event — polling `/updates` is usually more efficient than re-reading individual approvals.

Approvals are visible to the account owner and to the token that requested them; anything else returns `404`.

**Requirements:** `payments:read` scope. Works pre-claim.

## Request

<ParamField path="approvalId" type="string" required>
  The approval ID returned by a hire, fund, release, or end-contract request.
</ParamField>

## Response

<ResponseField name="approval" type="object">
  <Expandable title="approval" defaultOpen>
    <ResponseField name="id" type="string">
      Approval ID.
    </ResponseField>

    <ResponseField name="type" type="string">
      `proposal_hire`, `milestone_fund`, `milestone_approve`, or `contract_end`.
    </ResponseField>

    <ResponseField name="status" type="string">
      `pending`, `confirmed`, `declined`, or `expired`.
    </ResponseField>

    <ResponseField name="contractId" type="string | null">
      The contract the action targets. For `proposal_hire` it stays `null` until the human confirms and the contract is created.
    </ResponseField>

    <ResponseField name="milestoneId" type="string | null">
      The milestone the action targets; `null` for `contract_end` and `proposal_hire`.
    </ResponseField>

    <ResponseField name="jobId" type="string | null">
      The job the contract belongs to.
    </ResponseField>

    <ResponseField name="proposalId" type="string | null">
      The proposal being hired for `proposal_hire`; `null` for the other types.
    </ResponseField>

    <ResponseField name="approvalUrl" type="string">
      Where the human confirms or declines — share when `status` is `pending`.
    </ResponseField>

    <ResponseField name="expiresAt" type="string">
      ISO expiry timestamp (\~72h after creation).
    </ResponseField>

    <ResponseField name="resolvedAt" type="string | null">
      ISO timestamp of confirmation/decline/expiry; `null` while pending.
    </ResponseField>

    <ResponseField name="result" type="object | null">
      Execution outcome once confirmed (e.g. `{invoiceId}` for funding); `null` otherwise.
    </ResponseField>

    <ResponseField name="createdAt" type="string">
      ISO creation timestamp.
    </ResponseField>
  </Expandable>
</ResponseField>

## Errors

| Status | `code`         | Meaning                                                                                             |
| ------ | -------------- | --------------------------------------------------------------------------------------------------- |
| `401`  | `UNAUTHORIZED` | Missing or invalid token                                                                            |
| `403`  | `FORBIDDEN`    | Missing `payments:read` scope                                                                       |
| `404`  | `NOT_FOUND`    | No such approval, or it belongs to another account (`details: {resource: "approvals", approvalId}`) |

<RequestExample>
  ```bash curl theme={null}
  curl -sS https://app.opentrain.ai/api/public/v1/approvals/<APPROVAL_ID> \
    -H "Authorization: Bearer $OT_API_TOKEN"
  ```

  ```bash CLI theme={null}
  opentrain approvals get --approval-id <APPROVAL_ID> --json
  ```

  ```json MCP: opentrain_get_approval theme={null}
  {
    "approvalId": "<APPROVAL_ID>"
  }
  ```
</RequestExample>

<ResponseExample>
  ```json 200 (confirmed) theme={null}
  {
    "approval": {
      "id": "<APPROVAL_ID>",
      "type": "milestone_fund",
      "status": "confirmed",
      "contractId": "<CONTRACT_ID>",
      "milestoneId": "<MILESTONE_ID>",
      "jobId": "<JOB_ID>",
      "proposalId": null,
      "approvalUrl": "https://app.opentrain.ai/approvals/<APPROVAL_ID>",
      "expiresAt": "2026-06-15T10:00:00.000Z",
      "resolvedAt": "2026-06-12T14:30:00.000Z",
      "result": {
        "invoiceId": "<INVOICE_ID>"
      },
      "createdAt": "2026-06-12T10:00:00.000Z"
    }
  }
  ```

  ```json 200 (still pending) theme={null}
  {
    "approval": {
      "id": "<APPROVAL_ID>",
      "type": "milestone_fund",
      "status": "pending",
      "contractId": "<CONTRACT_ID>",
      "milestoneId": "<MILESTONE_ID>",
      "jobId": "<JOB_ID>",
      "proposalId": null,
      "approvalUrl": "https://app.opentrain.ai/approvals/<APPROVAL_ID>",
      "expiresAt": "2026-06-15T10:00:00.000Z",
      "resolvedAt": null,
      "result": null,
      "createdAt": "2026-06-12T10:00:00.000Z"
    }
  }
  ```
</ResponseExample>
