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

> ## Agent Instructions
> When building application code, use `@naturalpay/sdk` for TypeScript or `naturalpay` for Python.
> When operating Natural directly for a user, use the payments MCP at `https://mcp.natural.com`.
> When searching Natural documentation, use the docs MCP at `https://docs.natural.com/mcp`.
> Use the Natural CLI for terminal and CI automation.
> Use REST only for unsupported languages or when the user explicitly requests raw HTTP.
> Start integration development and testing in the sandbox. Do not use production unless the user explicitly requests it.
> For sandbox requests that require `customerPartyId`, list customers first. Reuse only the intended fixture; otherwise create a customer.
> REST and SDK amounts use integer minor units. Payments MCP amounts use decimal strings with a required currency code.

# Approve or deny a held payment

> Approve or deny a payment held for review

Release or deny a payment that a limit put on hold.

<Snippet file="shared/prerequisites.mdx" />

<Note>
  When a payment breaches one of your limits, Natural does not reject it. Natural holds the payment
  and opens an approval (`apr_*`). The call that sent the payment still returns `2xx`, and no money
  moves until someone approves. See the [Approvals overview](/guides/concepts/approvals).
</Note>

## List what is held

[`GET /approvals`](/api-reference/approvals/list-approvals) lists pending holds. `status` accepts `pending`, `approved`, `denied`, or `canceled`.

<CodeGroup>
  ```python Python theme={null}
  approvals = client.approvals.list(status="pending")
  ```

  ```typescript TypeScript theme={null}
  const approvals = await client.approvals.list({ status: "pending" });
  ```

  ```bash CLI theme={null}
  natural approvals list --status pending --limit 50
  ```

  ```bash cURL theme={null}
  curl "https://api.natural.com/approvals?status=pending&limit=50" \
    -H "Authorization: Bearer $NATURAL_API_KEY"
  ```
</CodeGroup>

Each record names the payment it holds and every reason it was held:

<Snippet file="api-examples/approvals.list.response.mdx" />

## Approve or deny

[`POST /approvals/{approvalId}/approve`](/api-reference/approvals/approve-payment-or-transfer) releases the original payment. [`POST /approvals/{approvalId}/deny`](/api-reference/approvals/deny-payment-or-transfer) ends it in `APPROVAL_DENIED`. Send `reason` (up to 500 characters) to record why.

<CodeGroup>
  ```python Python theme={null}
  import uuid

  client.approvals.approve("apr_019cd1798d8a74dd75c16fc6d843db81", idempotency_key=str(uuid.uuid4()))
  # or
  client.approvals.deny(
      "apr_019cd1798d8a74dd75c16fc6d843db81",
      reason="Over budget for this vendor",
      idempotency_key=str(uuid.uuid4()),
  )
  ```

  ```typescript TypeScript theme={null}
  await client.approvals.approve({
    approvalId: "apr_019cd1798d8a74dd75c16fc6d843db81",
    idempotencyKey: crypto.randomUUID(),
  });
  // or
  await client.approvals.deny({
    approvalId: "apr_019cd1798d8a74dd75c16fc6d843db81",
    reason: "Over budget for this vendor",
    idempotencyKey: crypto.randomUUID(),
  });
  ```

  ```bash CLI theme={null}
  natural approvals approve --approval-id apr_019cd1798d8a74dd75c16fc6d843db81 --idempotency-key "$(uuidgen)"
  # or
  natural approvals deny --approval-id apr_019cd1798d8a74dd75c16fc6d843db81 --json '{"reason": "Over budget for this vendor"}' --idempotency-key "$(uuidgen)"
  ```

  ```bash cURL theme={null}
  curl -X POST https://api.natural.com/approvals/apr_019cd1798d8a74dd75c16fc6d843db81/approve \
    -H "Authorization: Bearer $NATURAL_API_KEY" \
    -H "Idempotency-Key: $(uuidgen)"
  ```
</CodeGroup>

The record comes back resolved, with `status` now `approved` and `resolvedAt` set:

<Snippet file="api-examples/approvals.approve.response.mdx" />

Approving clears only the gate you own. If the payment also breached a gate owned by someone else, it stays held until that owner acts too. When several breached gates share one owner, they merge into one hold that lists every reason, and the highest breached limit is the one you are clearing.

<Snippet file="shared/webhook-approval.mdx" />


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.