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

# Request Purchase Approval

Ask the user to approve a product purchase before any money moves. Sends an approval card to the org's chat destinations (Slack gets one-tap Approve; other surfaces get a reply instruction) with the current quote pinned — the approved purchase executes with exactly the price and cap shown. Use this as the final node of price-watch / availability workflows instead of order-product, which is reserved for manual-trigger workflows. Ideal for: price-drop alerts that buy on approval, restock watches, any automated purchase that should keep a human on the trigger.

Catalog action Integrations

Ask the user to approve a product purchase before any money moves. Sends an approval card to the org's chat destinations (Slack gets one-tap Approve; other surfaces get a reply instruction) with the current quote pinned — the approved purchase executes with exactly the price and cap shown. Use this as the final node of price-watch / availability workflows instead of order-product, which is reserved for manual-trigger workflows. Ideal for: price-drop alerts that buy on approval, restock watches, any automated purchase that should keep a human on the trigger.


## At a Glance

| Field | Value |
| --- | --- |
| Action ID | `request-purchase-approval` |
| Category | Integrations |
| Connector | Not required |
| Requires gas | No |
| Funds movement | None declared |
| Tags | `shopping`, `purchase`, `notification` |

## Payload Schema

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `walletId` | `string` | Yes | Org wallet id \(wal_...\) that the approved purchase will pay USDC from. This exact id is carried into the approval card and used to execute the one-shot order, so it must be the org-wallet row id the order-product node would reference — not a Turnkey/provider id. |
| `productUrl` | `string` | Yes | Product URL to request approval for \(e.g. https://www.amazon.com/dp/B01N5IB20Q or https://www.walmart.com/ip/123456789\). A bare 10-character Amazon ASIN is also accepted. |
| `quantity` | `number` | No | Number of units \(1-10\). Default: 1. |
| `itemPriceCents` | `number` | Yes | Current listed per-unit price in integer USD cents \(wire from an upstream get-product-details node\). PINNED into the approval card — the approved purchase executes with exactly this quote. |
| `maxTotalCents` | `number` | No | Optional authorized product cap in integer cents, including tax and shipping. Defaults to the item subtotal plus a 15% headroom buffer. Becomes the hard ceiling of the approved purchase. |
| `shippingAddress` | `object` | Yes | US shipping address the approved order will ship to. |
| `chainId` | `number` | No | Chain the approved purchase will pay from in USDC. Supported: 8453 \(Base\), 1 \(Ethereum\), 42161 \(Arbitrum\), 10 \(Optimism\), 137 \(Polygon\). Default: 8453. |
| `paymentMethod` | `string` | No | How the approved purchase will be funded: 'usdc' for a crypto wallet, 'airwallex' when walletId names a connected Airwallex balance. Affects only how an explicit maxTotalCents is read — as the product cap on usdc, as the all-in ceiling on airwallex. The figure on the card is what gets charged either way, so a value that does not match the wallet can never overcharge — the run is refused above the figure on the card. Getting it wrong fails the purchase rather than mispricing it: the value is pinned onto the approval as expectedPaymentMethod, and order-product refuses with PAYMENT_METHOD_MISMATCH when the selected wallet settles on the other rail. Declaring 'airwallex' for a crypto wallet can also fail with CHARGE_EXCEEDS_APPROVED, since the same figure read as an all-in ceiling is a smaller product cap. Default: 'usdc'. |
| `note` | `string` | No | Optional context shown on the approval card \(e.g. 'price dropped below your $40 target'\). |

## Result Schema

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `status` | `string` | Yes | Approval request delivery status. |
| `delivered` | `number` | Yes | Number of notification destinations the approval card reached. |
| `failed` | `number` | Yes | Number of destinations that could not be reached. |

## Examples

**Workflow node**

```json
{
  "type": "request-purchase-approval",
  "payload": {
    "productUrl": "https://example.com/webhook",
    "itemPriceCents": 1,
    "shippingAddress": {
      "firstName": "example-firstName",
      "lastName": "example-lastName",
      "addressLine1": "example-addressLine1",
      "city": "example-city",
      "state": "example-state",
      "zipCode": "98101",
      "phoneNumber": "example-phoneNumber"
    },
    "walletId": "0x0000000000000000000000000000000000000000"
  },
  "children": []
}
```
  **Test with API**

```bash
curl -X POST "https://api.b3os.org/v1/actions/request-purchase-approval/test" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "inputs": {
    "productUrl": "https://example.com/webhook",
    "itemPriceCents": 1,
    "shippingAddress": {
      "firstName": "example-firstName",
      "lastName": "example-lastName",
      "addressLine1": "example-addressLine1",
      "city": "example-city",
      "state": "example-state",
      "zipCode": "98101",
      "phoneNumber": "example-phoneNumber"
    },
    "walletId": "0x0000000000000000000000000000000000000000"
  }
}'
```

**Use expressions for dynamic values**

Payload fields can use workflow expressions such as `{{$trigger.body.amount}}`, `{{$nodes.fetch.result.price}}`, and `{{$props.asset}}` when the value should come from a trigger, prior node, or reusable workflow prop.