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
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": []}
bashcurl -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" }}'
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.
