docs(payments): update AgentCore payments tutorials (#1507)
--------- Co-authored-by: Anil Nadiminti <anilnadi@amazon.com>
This commit is contained in:
+11
-1
@@ -1,4 +1,14 @@
|
||||
# ── AgentCore payments: Coinbase CDP Setup ───────────────────────
|
||||
#
|
||||
# ⚠️ SECURITY WARNING: This .env pattern is for LOCAL DEVELOPMENT ONLY.
|
||||
# DEPLOYED WORKLOADS: Use AWS Secrets Manager or Systems Manager Parameter Store.
|
||||
# See: https://docs.aws.amazon.com/secretsmanager/latest/userguide/intro.html
|
||||
#
|
||||
# Example — retrieve credentials from Secrets Manager in Python:
|
||||
# import boto3, json
|
||||
# secret = boto3.client("secretsmanager").get_secret_value(SecretId="coinbase-credentials")
|
||||
# creds = json.loads(secret["SecretString"])
|
||||
#
|
||||
# Copy this file to .env and fill in your values:
|
||||
# cp .env.coinbase.sample .env
|
||||
|
||||
@@ -15,7 +25,7 @@ AWS_REGION=us-west-2
|
||||
|
||||
# ── Coinbase CDP Credentials ─────────────────────────────────────
|
||||
# TUTORIAL ONLY: For local testing, store credentials in .env (git-ignored).
|
||||
# PRODUCTION: Use AWS Secrets Manager or Systems Manager Parameter Store.
|
||||
# DEPLOYED WORKLOADS: Use AWS Secrets Manager or Systems Manager Parameter Store.
|
||||
# See: https://docs.aws.amazon.com/secretsmanager/latest/userguide/intro.html
|
||||
# Get these from portal.cdp.coinbase.com (see providers/coinbase_cdp_account_setup.ipynb)
|
||||
# API Key ID + Secret: from project API key creation
|
||||
|
||||
+11
-1
@@ -1,4 +1,14 @@
|
||||
# ── AgentCore payments: Stripe (Privy) Setup ─────────────────────
|
||||
#
|
||||
# ⚠️ SECURITY WARNING: This .env pattern is for LOCAL DEVELOPMENT ONLY.
|
||||
# DEPLOYED WORKLOADS: Use AWS Secrets Manager or Systems Manager Parameter Store.
|
||||
# See: https://docs.aws.amazon.com/secretsmanager/latest/userguide/intro.html
|
||||
#
|
||||
# Example — retrieve credentials from Secrets Manager in Python:
|
||||
# import boto3, json
|
||||
# secret = boto3.client("secretsmanager").get_secret_value(SecretId="privy-credentials")
|
||||
# creds = json.loads(secret["SecretString"])
|
||||
#
|
||||
# Copy this file to .env and fill in your values:
|
||||
# cp .env.privy.sample .env
|
||||
#
|
||||
@@ -19,7 +29,7 @@ AWS_REGION=us-west-2
|
||||
|
||||
# ── Privy Credentials ────────────────────────────────────────────
|
||||
# TUTORIAL ONLY: For local testing, store credentials in .env (git-ignored).
|
||||
# PRODUCTION: Use AWS Secrets Manager or Systems Manager Parameter Store.
|
||||
# DEPLOYED WORKLOADS: Use AWS Secrets Manager or Systems Manager Parameter Store.
|
||||
# See: https://docs.aws.amazon.com/secretsmanager/latest/userguide/intro.html
|
||||
# Get these from dashboard.privy.io (see providers/stripe_privy_account_setup.ipynb)
|
||||
# The provider notebook writes these automatically — only fill manually if skipping it.
|
||||
|
||||
+13
-7
@@ -1,12 +1,18 @@
|
||||
# ── AgentCore payments: Environment Configuration ────────────────
|
||||
#
|
||||
# SECURITY NOTICE:
|
||||
# This .env file is for LOCAL DEVELOPMENT AND TESTING ONLY.
|
||||
# For production deployments:
|
||||
# - Use AWS Secrets Manager or Systems Manager Parameter Store
|
||||
# - Never commit .env files to version control (already in .gitignore)
|
||||
# - Rotate credentials regularly
|
||||
# - Follow the principle of least privilege for IAM roles
|
||||
# ⚠️ SECURITY WARNING: This .env pattern is for LOCAL DEVELOPMENT ONLY.
|
||||
#
|
||||
# For deployed workloads:
|
||||
# - Store credentials in AWS Secrets Manager or Systems Manager Parameter Store.
|
||||
# See: https://docs.aws.amazon.com/secretsmanager/latest/userguide/intro.html
|
||||
# - Never commit .env files to version control (already in .gitignore).
|
||||
# - Rotate credentials regularly.
|
||||
# - Follow the principle of least privilege for IAM roles.
|
||||
#
|
||||
# Example — retrieve credentials from Secrets Manager in Python:
|
||||
# import boto3, json
|
||||
# secret = boto3.client("secretsmanager").get_secret_value(SecretId="my-payment-creds")
|
||||
# creds = json.loads(secret["SecretString"])
|
||||
#
|
||||
# Pick your provider and copy the matching sample:
|
||||
#
|
||||
|
||||
+82
-10
@@ -37,7 +37,7 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"!pip install -r requirements.txt --quiet"
|
||||
"%pip install -r requirements.txt --quiet"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -114,7 +114,11 @@
|
||||
"cell_type": "markdown",
|
||||
"id": "f6bdaeee",
|
||||
"metadata": {},
|
||||
"source": "## Step 1 — Create One Shared Payment Manager\n\n> **Cost notice:** Payment Managers, Connectors, and Instruments incur AWS charges while provisioned. Run cleanup when finished."
|
||||
"source": [
|
||||
"## Step 1 — Create One Shared Payment Manager\n",
|
||||
"\n",
|
||||
"> **Cost notice:** Payment Managers, Connectors, and Instruments incur AWS charges while provisioned. Run cleanup when finished."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
@@ -278,7 +282,21 @@
|
||||
"cell_type": "markdown",
|
||||
"id": "e1c36340",
|
||||
"metadata": {},
|
||||
"source": "## Step 5 — Fund Both Wallets + Complete Consent\n\nFund both wallets at [faucet.circle.com](https://faucet.circle.com/):\n- `ETHEREUM` → **Base Sepolia**\n- `SOLANA` → **Solana Devnet**\n\n### StripePrivy — run the Privy reference frontend\n\nThe StripePrivy wallet above won't accept payments until the end user grants your agent signing permission. Follow **Step 3** of [providers/stripe_privy_account_setup.ipynb](providers/stripe_privy_account_setup.ipynb) if you haven't already — it walks through the Privy reference frontend from `github.com/privy-io/aws-agentcore-sdk`.\n\nIf the Privy reference frontend is already running from that notebook: reload it in your browser so the page picks up the StripePrivy wallet created above, then choose **Connect agent** once. That adds AgentCore as an *additional signer* on every Privy wallet attached to the logged-in user. Re-choosing later is safe.\n\n> **CoinbaseCDP** uses project-level delegation configured in the [CDP Portal](https://portal.cdp.coinbase.com/), not a per-wallet action. See Tutorial 00's Step 7b for details."
|
||||
"source": [
|
||||
"## Step 5 — Fund Both Wallets + Complete Consent\n",
|
||||
"\n",
|
||||
"Fund both wallets at [faucet.circle.com](https://faucet.circle.com/):\n",
|
||||
"- `ETHEREUM` → **Base Sepolia**\n",
|
||||
"- `SOLANA` → **Solana Devnet**\n",
|
||||
"\n",
|
||||
"### StripePrivy — run the Privy reference frontend\n",
|
||||
"\n",
|
||||
"The StripePrivy wallet above won't accept payments until the end user grants your agent signing permission. Follow **Step 3** of [providers/stripe_privy_account_setup.ipynb](providers/stripe_privy_account_setup.ipynb) if you haven't already — it walks through the Privy reference frontend from `github.com/privy-io/aws-agentcore-sdk`.\n",
|
||||
"\n",
|
||||
"If the Privy reference frontend is already running from that notebook: reload it in your browser so the page picks up the StripePrivy wallet created above, then choose **Connect agent** once. That adds AgentCore as an *additional signer* on every Privy wallet attached to the logged-in user. Re-choosing later is safe.\n",
|
||||
"\n",
|
||||
"> **CoinbaseCDP** uses project-level delegation configured in the [CDP Portal](https://portal.cdp.coinbase.com/), not a per-wallet action. See Tutorial 00's Step 7b for details."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
@@ -286,7 +304,16 @@
|
||||
"id": "ea1b415d",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": "print('Fund these wallets at https://faucet.circle.com/\\n')\nfor label, inst in instruments.items():\n print(f' {label:15s} → {inst[\"wallet_address\"]}')\nprint(f'\\n Network: {NETWORK}')\nprint()\nprint(f' StripePrivy: reload the Privy reference frontend you set up in the Privy provider notebook,')\nprint(f' then choose Connect agent once to grant AgentCore signer access on all Privy wallets')\nprint(f' linked to {os.environ.get(\"LINKED_EMAIL\", \"user@example.com\")}.')"
|
||||
"source": [
|
||||
"print('Fund these wallets at https://faucet.circle.com/\\n')\n",
|
||||
"for label, inst in instruments.items():\n",
|
||||
" print(f' {label:15s} → {inst[\"wallet_address\"]}')\n",
|
||||
"print(f'\\n Network: {NETWORK}')\n",
|
||||
"print()\n",
|
||||
"print(f' StripePrivy: reload the Privy reference frontend you set up in the Privy provider notebook,')\n",
|
||||
"print(f' then choose Connect agent once to grant AgentCore signer access on all Privy wallets')\n",
|
||||
"print(f' linked to {os.environ.get(\"LINKED_EMAIL\", \"user@example.com\")}.')"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
@@ -294,7 +321,30 @@
|
||||
"id": "cdaa5cd8",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": "# StripePrivy: confirm signer access actually landed on the wallet.\n# Skipped for CoinbaseCDP — delegation is handled at the CDP project level, not per-wallet.\nfrom utils import verify_privy_signer_on_wallet\n\nprivy_wallet = instruments['stripe_privy']['wallet_address']\ntry:\n ok = verify_privy_signer_on_wallet(\n app_id=require_env('PRIVY_APP_ID'),\n app_secret=require_env('PRIVY_APP_SECRET'),\n wallet_address_or_id=privy_wallet,\n quorum_id=require_env('PRIVY_AUTHORIZATION_ID'),\n )\nexcept Exception as exc:\n print(f' ⚠️ Consent check skipped: {exc}')\n print(' Choose Connect agent in the Privy reference frontend, then re-run this cell.')\nelse:\n if ok:\n print(f' ✅ Signer access granted on {privy_wallet}')\n else:\n print(f' ❌ Signer access has NOT been granted on {privy_wallet}.')\n print(' Reload the Privy reference frontend, choose Connect agent, then re-run this cell.')\n print(' ProcessPayment requires delegated signing on this instrument to succeed.')"
|
||||
"source": [
|
||||
"# StripePrivy: confirm signer access actually landed on the wallet.\n",
|
||||
"# Skipped for CoinbaseCDP — delegation is handled at the CDP project level, not per-wallet.\n",
|
||||
"from utils import verify_privy_signer_on_wallet\n",
|
||||
"\n",
|
||||
"privy_wallet = instruments['stripe_privy']['wallet_address']\n",
|
||||
"try:\n",
|
||||
" ok = verify_privy_signer_on_wallet(\n",
|
||||
" app_id=require_env('PRIVY_APP_ID'),\n",
|
||||
" app_secret=require_env('PRIVY_APP_SECRET'),\n",
|
||||
" wallet_address_or_id=privy_wallet,\n",
|
||||
" quorum_id=require_env('PRIVY_AUTHORIZATION_ID'),\n",
|
||||
" )\n",
|
||||
"except Exception as exc:\n",
|
||||
" print(f' ⚠️ Consent check skipped: {exc}')\n",
|
||||
" print(' Choose Connect agent in the Privy reference frontend, then re-run this cell.')\n",
|
||||
"else:\n",
|
||||
" if ok:\n",
|
||||
" print(f' ✅ Signer access granted on {privy_wallet}')\n",
|
||||
" else:\n",
|
||||
" print(f' ❌ Signer access has NOT been granted on {privy_wallet}.')\n",
|
||||
" print(' Reload the Privy reference frontend, choose Connect agent, then re-run this cell.')\n",
|
||||
" print(' ProcessPayment requires delegated signing on this instrument to succeed.')"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
@@ -363,13 +413,35 @@
|
||||
"cell_type": "markdown",
|
||||
"id": "921a3dba",
|
||||
"metadata": {},
|
||||
"source": "## What This Demonstrates\n\nOne Payment Manager, two wallet providers, same session budget. The agent code in Tutorial 01+ doesn't change — Select which `instrument_id` to pass to the plugin."
|
||||
"source": [
|
||||
"## What This Demonstrates\n",
|
||||
"\n",
|
||||
"One Payment Manager, two wallet providers, same session budget. The agent code in Tutorial 01+ doesn't change — Select which `instrument_id` to pass to the plugin."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "verification-multi-provider",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Verification\n",
|
||||
"\n",
|
||||
"If the cells above ran without errors, both connectors are active. You should see two Payment Instruments printed above — one for Coinbase CDP and one for StripePrivy — each with an `ACTIVE` status and a unique `walletAddress`."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "09104d35",
|
||||
"source": "## Cleanup\n\n**Cost notice:** Payment Managers, Connectors, and Instruments may incur AWS charges while provisioned. Delete them when no longer needed.\n\nSessions expire automatically after their configured `expiryTimeInMinutes`. To delete all payment resources created in this tutorial, run the cleanup cell at the bottom of Tutorial 00 (`setup_agentcore_payments.ipynb`). Deleting the Payment Manager cascades to all child resources (Connectors, Instruments).",
|
||||
"metadata": {}
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Cleanup\n",
|
||||
"\n",
|
||||
"> **Warning:** Deleting the Payment Manager permanently removes all child resources (Connectors, Credential Providers, Instruments) and cannot be undone. Confirm you have completed all downstream tutorials before cleaning up.\n",
|
||||
"\n",
|
||||
"**Cost notice:** Please see AgentCore pricing for more details on cost for the services used - https://aws.amazon.com/bedrock/agentcore/pricing/\n",
|
||||
"\n",
|
||||
"Sessions expire automatically after their configured `expiryTimeInMinutes`. To delete all payment resources created in this tutorial, run the cleanup cell at the bottom of Tutorial 00 (`setup_agentcore_payments.ipynb`). Deleting the Payment Manager cascades to all child resources (Connectors, Instruments)."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
@@ -384,7 +456,7 @@
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": ".venv",
|
||||
"display_name": "Python 3 (ipykernel)",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
@@ -398,7 +470,7 @@
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.12.11"
|
||||
"version": "3.14.4"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
|
||||
+21
-2
@@ -1,5 +1,7 @@
|
||||
# Set Up AgentCore payments
|
||||
|
||||
> **Cost notice:** This tutorial creates IAM roles, CloudWatch log groups, and AgentCore payment resources. These may incur AWS charges. Run the cleanup cell and delete IAM roles and log groups when finished.
|
||||
|
||||
## Overview
|
||||
|
||||
This tutorial walks you through the complete setup of Amazon Bedrock AgentCore payments using the AWS SDK (boto3). You'll create IAM roles, configure wallet credentials, and provision the payment stack — everything needed before building payment-enabled agents.
|
||||
@@ -58,13 +60,30 @@ Most of this tutorial is automated (run cells top to bottom). Three steps requir
|
||||
| When | What | Where | Time |
|
||||
|------|------|-------|------|
|
||||
| **Before running** | Get wallet provider credentials | Run `providers/coinbase_cdp_account_setup.ipynb` or `providers/stripe_privy_account_setup.ipynb` | ~15 min |
|
||||
| **Step 7b** | Fund wallet with testnet USDC | [faucet.circle.com](https://faucet.circle.com/) → paste wallet address → request 10 USDC | ~2 min |
|
||||
| **Step 7b** | Delegate signing permission | **Coinbase:** CDP Portal → Wallets → Embedded Wallet → Policies → enable Delegated Signing. **Privy:** Privy reference frontend at localhost:3000 → log in → choose Connect agent | ~5 min |
|
||||
| **Step 7b** | Fund wallet — step 1: open faucet | Go to [faucet.circle.com](https://faucet.circle.com/) | ~2 min |
|
||||
| **Step 7b** | Fund wallet — step 2: paste address | Paste your wallet address into the faucet form | |
|
||||
| **Step 7b** | Fund wallet — step 3: request USDC | Request 10 USDC and wait for confirmation | |
|
||||
| **Step 7b** | Delegate signing — Coinbase step 1 | Open the CDP Portal | ~5 min |
|
||||
| **Step 7b** | Delegate signing — Coinbase step 2 | Navigate to Wallets → Embedded Wallet → Policies | |
|
||||
| **Step 7b** | Delegate signing — Coinbase step 3 | Enable Delegated Signing | |
|
||||
| **Step 7b** | Delegate signing — Privy step 1 | Open the Privy reference frontend at localhost:3000 | |
|
||||
| **Step 7b** | Delegate signing — Privy step 2 | Log in with the end-user email | |
|
||||
| **Step 7b** | Delegate signing — Privy step 3 | Choose **Connect agent**, then **Give access** | |
|
||||
|
||||
Without the funding and delegation steps, `ProcessPayment` will fail in Tutorial 01. The notebook prints a clear ✋ ACTION callout when you reach Step 7b.
|
||||
|
||||
## Verification
|
||||
|
||||
After completing the notebook, verify the setup succeeded:
|
||||
|
||||
1. Confirm `.env` contains `PAYMENT_MANAGER_ARN`, `INSTRUMENT_ID`, and `SESSION_ID`.
|
||||
2. Run `aws sts get-caller-identity` to verify AWS credentials are active.
|
||||
3. Confirm the wallet has testnet USDC by checking the instrument balance output in Step 7.
|
||||
|
||||
## Cleanup
|
||||
|
||||
> **Warning:** Cleanup is irreversible and permanently deletes all payment resources (Manager, Connectors, Instruments) and associated transaction history. Confirm you have completed all downstream tutorials before running cleanup.
|
||||
|
||||
When done with all tutorials, clean up resources to avoid charges:
|
||||
|
||||
1. Run the cleanup cell at the bottom of `setup_agentcore_payments.ipynb` to delete the Payment Manager and all child resources.
|
||||
|
||||
+8
-2
@@ -44,8 +44,14 @@ The vendor is called `StripePrivy` but configuration is 100% Privy credentials.
|
||||
|
||||
Set `CREDENTIAL_PROVIDER_TYPE=StripePrivy` in your `.env`.
|
||||
|
||||
> **Important:** `PRIVY_AUTHORIZATION_ID` is the ID of your P-256 authorization key, not an API key. The `authorizationPrivateKey` must have the `wallet-auth:` prefix stripped — AgentCore's validation rejects the prefixed form.
|
||||
> **Important:** `PRIVY_AUTHORIZATION_ID` is the ID of your P-256 authorization key, not an API key. The `authorizationPrivateKey` must have the `wallet-auth:` prefix stripped — Bedrock AgentCore validation rejects the prefixed form.
|
||||
|
||||
## Cleanup
|
||||
|
||||
Credentials stored in `.env` are only used during the tutorial. For deployed workloads, store credentials in [AWS Secrets Manager](https://docs.aws.amazon.com/secretsmanager/latest/userguide/intro.html) instead of `.env` files.
|
||||
|
||||
> **Note:** AWS resources created using these credentials (IAM roles, Payment Manager, Connectors, Instruments) persist until explicitly deleted. Run the cleanup cell in Tutorial 00 to remove them when no longer needed.
|
||||
|
||||
## Conclusion
|
||||
|
||||
After completing the relevant provider setup guide, the required credentials are stored in the `.env` file. Return to Tutorial 00 to provision the AgentCore payments stack using these credentials.
|
||||
After completing the relevant provider setup guide, the required credentials are stored in the `.env` file. Return to [Tutorial 00](../setup_agentcore_payments.ipynb) to provision the AgentCore payments stack using these credentials.
|
||||
|
||||
+4
-2
@@ -12,7 +12,9 @@
|
||||
"cell_type": "markdown",
|
||||
"id": "cdp-01",
|
||||
"metadata": {},
|
||||
"source": "## Step 1 — Create a Coinbase Account\n\n1. Go to **[coinbase.com](https://coinbase.com/)**.\n2. Choose **Get started**.\n3. Enter an email address and create a password.\n4. Verify your email via the link Coinbase sends.\n5. Complete phone verification (SMS code).\n\n**Note:** If you already have a Coinbase account, skip to Step 2."
|
||||
"source": [
|
||||
"## Step 1 — Create a Coinbase Account\n\n1. Go to **[coinbase.com](https://coinbase.com/)**.\n2. Choose **Get started**.\n3. Enter an email address.\n4. Create a password.\n5. Verify your email via the link Coinbase sends.\n6. Complete phone verification (SMS code).\n\n**Note:** If you already have a Coinbase account, skip to Step 2."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
@@ -98,4 +100,4 @@
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
}
|
||||
|
||||
+26
-68
@@ -9,9 +9,13 @@
|
||||
"\n",
|
||||
"## Overview\n",
|
||||
"\n",
|
||||
"**Amazon Bedrock AgentCore payments** can use Privy as its wallet infrastructure. Privy provisions embedded wallets for your end users and stores private keys in a secure enclave — AgentCore never sees them.\n",
|
||||
"**Amazon Bedrock AgentCore payments** can use Privy as its wallet infrastructure. Privy provisions embedded wallets for your end users and stores private keys in a secure enclave — AgentCore does not have access to them.\n",
|
||||
"\n",
|
||||
"This guide walks you through creating a Privy app, generating an authorization key, and setting up the Privy reference frontend so end users can grant your agent permission to sign on their behalf.\n",
|
||||
"This guide walks you through three steps:\n",
|
||||
"\n",
|
||||
"1. Create a Privy app and copy your App ID and App Secret.\n",
|
||||
"2. Generate an authorization key and copy the key ID and private key.\n",
|
||||
"3. Set up the Privy reference frontend so end users can grant your agent permission to sign on their behalf.\n",
|
||||
"\n",
|
||||
"### What You'll Get\n",
|
||||
"\n",
|
||||
@@ -24,7 +28,7 @@
|
||||
"| `PRIVY_AUTHORIZATION_ID` | The key quorum ID for agent signing |\n",
|
||||
"| `PRIVY_AUTHORIZATION_PRIVATE_KEY` | P-256 private key AgentCore uses to authenticate to Privy |\n",
|
||||
"\n",
|
||||
"**Note:** The Authorization Private Key is shown only once in the Privy dashboard. Save it immediately — it cannot be retrieved later.\n",
|
||||
"**Note:** The Authorization Private Key is displayed once in the Privy dashboard. Copy it before closing the dialog.\n",
|
||||
"\n",
|
||||
"### Prerequisites\n",
|
||||
"\n",
|
||||
@@ -43,11 +47,11 @@
|
||||
"| 2 | dashboard.privy.io | Generate authorization key → copy `ID` + `Private Key` |\n",
|
||||
"| 3 | Your local terminal + browser | Run the Privy reference frontend on `http://localhost:3000` and verify login |\n",
|
||||
"\n",
|
||||
"Steps 1–2 populate your `.env`. Step 3 sets up the Privy reference frontend; the actual end-user consent click happens in Tutorial 00 Step 7b, after the wallet is created.\n",
|
||||
"Steps 1–2 populate your `.env`. Step 3 sets up the Privy reference frontend; the actual end-user consent step happens in Tutorial 00 Step 7b, after the wallet is created.\n",
|
||||
"\n",
|
||||
"### Next Step\n",
|
||||
"\n",
|
||||
"After completing this guide, return to [Tutorial 00](../setup_agentcore_payments.ipynb). Your `.env` will already be set up — the first code cell of this notebook writes `CREDENTIAL_PROVIDER_TYPE=StripePrivy` for you.\n"
|
||||
"After completing this guide, return to [Tutorial 00](../setup_agentcore_payments.ipynb). Your `.env` will already be set up — the first code cell of this notebook writes `CREDENTIAL_PROVIDER_TYPE=StripePrivy` for you."
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -68,18 +72,21 @@
|
||||
"source": [
|
||||
"## Step 1 — Create a Privy app\n",
|
||||
"\n",
|
||||
"> **Create a dedicated Privy app for AgentCore payments.** Keep it separate from any other Privy apps you operate — the allowed origins, authentication methods, and authorization key are all scoped to AgentCore's needs. Mixing them with another app's configuration makes both harder to reason about and easier to misconfigure.\n",
|
||||
"> **Create a dedicated Privy app for AgentCore payments.** Keep it separate from any other Privy apps you operate — the allowed origins, authentication methods, and authorization key are all scoped to the AgentCore payments configuration.\n",
|
||||
"\n",
|
||||
"1. Go to **[dashboard.privy.io](https://dashboard.privy.io)** and sign up (or log in) with your email. Privy sends a confirmation code — paste it to finish logging in.\n",
|
||||
"2. On the dashboard, click **New app**.\n",
|
||||
"3. Enter an app name (e.g. `AgentCore payments Tutorial`) and click **Create app**.\n",
|
||||
"4. The dialog shows your **App ID** and **App Secret**. Copy both — you'll paste them when you run the next cell.\n",
|
||||
"1. Go to **[dashboard.privy.io](https://dashboard.privy.io)** and sign up (or log in) with your email.\n",
|
||||
"2. Privy sends a confirmation code — paste it to finish logging in.\n",
|
||||
"3. On the dashboard, choose **New app**.\n",
|
||||
"4. Enter an app name (e.g. `AgentCore payments Tutorial`).\n",
|
||||
"5. Choose **Create app**.\n",
|
||||
"6. The dialog shows your **App ID** and **App Secret**. Copy both — you'll paste them when you run the next cell.\n",
|
||||
"\n",
|
||||
" \n",
|
||||
"\n",
|
||||
"5. Open **User management → Authentication**.\n",
|
||||
"6. Under **Basics**, make sure **Email** is enabled.\n",
|
||||
"7. Scroll down to **External wallets** and enable both **EVM wallets** and **SVM (Solana) wallets**.\n",
|
||||
"7. Open **User management → Authentication**.\n",
|
||||
"8. Under **Basics**, make sure **Email** is enabled.\n",
|
||||
"9. Scroll down to **External wallets**.\n",
|
||||
"10. Enable both **EVM wallets** and **SVM (Solana) wallets**.\n",
|
||||
"\n",
|
||||
"Now run the next cell. Two input prompts appear: paste the App ID in the first (visible), the App Secret in the second (hidden, shown as dots), pressing Enter after each.\n"
|
||||
]
|
||||
@@ -113,21 +120,7 @@
|
||||
"id": "87b29030",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Step 2 — Generate your authorization key\n",
|
||||
"\n",
|
||||
"AgentCore needs a P-256 authorization key to sign on behalf of your end users. Generate it in the Privy dashboard:\n",
|
||||
"\n",
|
||||
"1. In the Privy dashboard, make sure your app is selected in the left sidebar.\n",
|
||||
"2. Go to **Wallet Infrastructure → Authorization**.\n",
|
||||
"3. Click **New key**.\n",
|
||||
"4. In the dialog, enter a name (e.g. `Demo app key`) and click **Continue**. Privy generates a P-256 keypair and displays the **ID** and **Private Key**.\n",
|
||||
"5. Copy both values, then click **Save and close**.\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"Run the next cell, paste the values when prompted, and your `.env` will be updated.\n",
|
||||
"\n",
|
||||
"> Privy prefixes the private key with `wallet-auth:`. The next cell strips this prefix automatically — paste the value exactly as Privy displays it.\n"
|
||||
"## Step 2 — Generate your authorization key\n\nAgentCore needs a P-256 authorization key to sign on behalf of your end users. Generate it in the Privy dashboard:\n\n1. In the Privy dashboard, make sure your app is selected in the left sidebar.\n2. Go to **Wallet Infrastructure → Authorization**.\n3. Choose **New key**.\n4. In the dialog, enter a name (e.g. `Demo app key`).\n5. Choose **Continue**. Privy generates a P-256 keypair and displays the **ID** and **Private Key**.\n6. Copy both values.\n7. Choose **Save and close**.\n\n\n\nRun the next cell, paste the values when prompted, and your `.env` will be updated.\n\n> Privy prefixes the private key with `wallet-auth:`. The next cell strips this prefix automatically — paste the value exactly as Privy displays it."
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -230,25 +223,7 @@
|
||||
"cell_type": "markdown",
|
||||
"id": "0e6aed2e",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Now create `.env.local` in your `aws-agentcore-sdk/` directory and paste the contents into it.\n",
|
||||
"\n",
|
||||
"**macOS / Linux:**\n",
|
||||
"\n",
|
||||
"```bash\n",
|
||||
"# Still inside aws-agentcore-sdk\n",
|
||||
"nano .env.local # or: vim .env.local, or: open -a TextEdit .env.local\n",
|
||||
"# paste the contents, save, close\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"**Windows (PowerShell):**\n",
|
||||
"\n",
|
||||
"```powershell\n",
|
||||
"# Still inside aws-agentcore-sdk\n",
|
||||
"notepad .env.local\n",
|
||||
"# paste the contents, save, close\n",
|
||||
"```\n"
|
||||
]
|
||||
"source": "Now create `.env.local` in your `aws-agentcore-sdk/` directory and paste the contents into it.\n\n**macOS / Linux:**\n\n```bash\n# Still inside aws-agentcore-sdk\nnano .env.local # or: vim .env.local, or: open -a TextEdit .env.local\n# 1. Paste the contents\n# 2. Save the file\n# 3. Close the editor\n```\n\n**Windows (PowerShell):**\n\n```powershell\n# Still inside aws-agentcore-sdk\nnotepad .env.local\n# 1. Paste the contents\n# 2. Save the file\n# 3. Close the editor\n```\n"
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
@@ -286,7 +261,8 @@
|
||||
"\n",
|
||||
"1. In the Privy dashboard, open **Configuration → App settings → Domains**.\n",
|
||||
"2. Under **Allowed origins → Web & mobile web**, choose **+ Add**.\n",
|
||||
"3. Enter `http://localhost:3000` and save.\n",
|
||||
"3. Enter `http://localhost:3000`.\n",
|
||||
"4. Choose **Save**.\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"\n",
|
||||
@@ -296,32 +272,14 @@
|
||||
"> 2. Remove `http://localhost:3000` once it is no longer needed — keeping dev origins on a production app widens your attack surface.\n",
|
||||
"> 3. Use a **separate Privy app** for production. The AgentCore payments docs call this out explicitly: *\"Create a dedicated Privy app specifically for AgentCore operations. Do not reuse Privy apps that serve other purposes.\"* The same principle applies across environments — don't share a Privy app between dev, staging, and prod.\n",
|
||||
">\n",
|
||||
"> Plain HTTP is only tolerated for `localhost` during development. Privy enforces HTTPS for every other origin."
|
||||
"> Plain HTTP is only tolerated for `localhost` during development. Privy enforces HTTPS for every other origin.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "2d831bf2",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### 3e. Log in to verify the Privy reference frontend works\n",
|
||||
"\n",
|
||||
"You're verifying the Privy reference frontend is wired up correctly. The actual **consent step** — granting the agent permission to sign on the user's behalf — happens later, in `setup_agentcore_payments.ipynb` **Step 7b**, after AgentCore provisions the wallet.\n",
|
||||
"\n",
|
||||
"1. Open **[http://localhost:3000](http://localhost:3000)** in your browser.\n",
|
||||
"2. Enter the email you want to use as the end-user account. This represents a *user of your app*, not you as the developer. Use the **same email** you plan to set as `LINKED_EMAIL` in `.env`.\n",
|
||||
" \n",
|
||||
"3. Submit the 6-digit code Privy sends to that email.\n",
|
||||
" \n",
|
||||
"\n",
|
||||
"That's it for this notebook. You should see the logged-in view. **Keep this browser tab open** — you'll come back to it in Step 7b.\n",
|
||||
"\n",
|
||||
"---\n",
|
||||
"\n",
|
||||
"> **Why no \"Connect agent\" click here?** The consent flow registers AgentCore as an *additional signer* on the end user's Privy wallet. At this point in the setup, no wallet exists yet on the AgentCore side. `CreatePaymentInstrument` (Step 7 of the main notebook) is what creates the wallet. Once the wallet exists, Step 7b walks you through the consent step, and a helper cell in the main notebook verifies signer access landed via the Privy API before you move on.\n",
|
||||
"\n",
|
||||
"> **Canonical wording from the AgentCore payments docs:** signer delegation lets the developer's backend *sign transactions on behalf of the end user* — it is authorization, not actual co-signing."
|
||||
]
|
||||
"source": "### 3e. Log in to verify the Privy reference frontend works\n\nYou're verifying the Privy reference frontend is wired up correctly. The actual **consent step** — granting the agent permission to sign on the user's behalf — happens later, in `setup_agentcore_payments.ipynb` **Step 7b**, after AgentCore provisions the wallet.\n\n1. Open **[http://localhost:3000](http://localhost:3000)** in your browser.\n2. Enter the email you want to use as the end-user account. This represents a *user of your app*, not you as the developer. Use the **same email** you plan to set as `LINKED_EMAIL` in `.env`.\n \n3. Submit the 6-digit code Privy sends to that email.\n \n\nThat's it for this notebook. You should see the logged-in view. **Keep this browser tab open** — you'll come back to it in Step 7b.\n\n---\n\n> **Why no \"Connect agent\" step here?** The consent flow registers AgentCore as an *additional signer* on the end user's Privy wallet. At this point in the setup, no wallet exists yet on the AgentCore side. `CreatePaymentInstrument` (Step 7 of the main notebook) is what creates the wallet. Once the wallet exists, Step 7b walks you through the consent step, and a helper cell in the main notebook verifies signer access landed via the Privy API before you move on.\n\n> **Canonical wording from the AgentCore payments docs:** signer delegation lets the developer's backend *sign transactions on behalf of the end user* — it is authorization, not actual co-signing."
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
|
||||
+20
-26
@@ -5,7 +5,7 @@
|
||||
"id": "c422adc5",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Setting Up Amazon Bedrock AgentCore payments\n",
|
||||
"# Setting Up Amazon Bedrock AgentCore Payments\n",
|
||||
"\n",
|
||||
"## Overview\n",
|
||||
"\n",
|
||||
@@ -13,6 +13,8 @@
|
||||
"\n",
|
||||
"**Amazon Bedrock AgentCore payments** handles all of this. This tutorial sets up the complete payment stack that all downstream tutorials depend on.\n",
|
||||
"\n",
|
||||
"> **Cost notice:** While this tutorial uses testnet USDC with no real-world value, the AWS infrastructure (AgentCore payments API calls, Secrets Manager storage, CloudWatch logs) incurs standard AWS charges. Persistent resources contribute to ongoing costs until cleaned up. See the Cleanup section at the bottom.\n",
|
||||
"\n",
|
||||
"### Tutorial Details\n",
|
||||
"\n",
|
||||
"| Information | Details |\n",
|
||||
@@ -50,16 +52,6 @@
|
||||
"All combinations use **embedded wallets** (`EMBEDDED_CRYPTO_WALLET`) with `linkedAccounts` for user identity. Set `CREDENTIAL_PROVIDER_TYPE` and `NETWORK` in your `.env` to choose. The agent code in downstream tutorials is identical regardless of your choice."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "diagram_resource_hierarchy",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Resource Hierarchy\n",
|
||||
"\n",
|
||||
"\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "30763f2a",
|
||||
@@ -130,7 +122,7 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"!pip install -r requirements.txt --quiet"
|
||||
"%pip install -r requirements.txt --quiet"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -186,9 +178,9 @@
|
||||
"\n",
|
||||
"### Why separate roles?\n",
|
||||
"\n",
|
||||
"The role separation enforces a security boundary between the application backend and the runtime process. The application backend (ManagementRole) creates instruments and sessions with spending limits. The runtime process (ProcessPaymentRole) runs deterministic code that calls `ProcessPayment` on behalf of the agent — the agent (LLM) never calls `ProcessPayment` directly. The runtime cannot create sessions, override limits, or provision new wallets. This ensures the code that sets budgets is structurally separated from the code that processes payments, maintaining budget control.\n",
|
||||
"The role separation enforces a security boundary between the application backend and the runtime process. The application backend (ManagementRole) creates instruments and sessions with spending limits. The runtime process (ProcessPaymentRole) runs deterministic code that calls `ProcessPayment` on behalf of the agent — the agent (LLM) never calls `ProcessPayment` directly. The runtime cannot create sessions, override limits, or provision new wallets. This structurally separates the code that sets budgets from the code that processes payments, maintaining budget control.\n",
|
||||
"\n",
|
||||
"The ManagementRole has an explicit Deny on `ProcessPayment` for the same reason: the code that sets budgets should never execute payments. This is structural — enforced by IAM, not application logic. You can read more about roles in the [official AWS docs](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/payments-iam-roles.html#payments-iam-why-separation)"
|
||||
"The ManagementRole has an explicit Deny on `ProcessPayment` for the same reason: the code that sets budgets should never process payments. This is structural — enforced by IAM, not application logic. You can read more about roles in the [official AWS docs](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/payments-iam-roles.html#payments-iam-why-separation)\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -345,7 +337,7 @@
|
||||
"* **Control Plane** (`bedrock-agentcore-control`) — manages the payment stack (Manager, Connector, Credential Provider)\n",
|
||||
"* **Data Plane** (`bedrock-agentcore`) — runs payment operations (Instrument, Session, ProcessPayment)\n",
|
||||
"\n",
|
||||
"We assume the appropriate IAM role for each:\n",
|
||||
"The cells below assume the appropriate IAM role for each:\n",
|
||||
"* `ControlPlaneRole` → `cp_client` — for Steps 4–6\n",
|
||||
"* `ManagementRole` → `dp_client` — for Steps 7–8"
|
||||
]
|
||||
@@ -380,7 +372,7 @@
|
||||
"\n",
|
||||
"A **PaymentCredentialProvider** stores your wallet provider credentials (Coinbase API keys or Privy keys) securely inside AgentCore Identity. After ingestion, the credentials are never returned to your code — the service retrieves them at runtime via the ResourceRetrievalRole.\n",
|
||||
"\n",
|
||||
"Your agent never sees private keys. This is a core security property of AgentCore payments."
|
||||
"The wallet provider holds key material. AgentCore retrieves credentials at runtime via the ResourceRetrievalRole — the agent code does not handle private keys directly."
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -730,9 +722,9 @@
|
||||
"\n",
|
||||
"1. The Privy reference frontend you launched in `providers/stripe_privy_account_setup.ipynb` (Step 6) handles this.\n",
|
||||
"2. Open [http://localhost:3000](http://localhost:3000) in your browser and log in with the **same email** you used as `LINKED_EMAIL` in `.env`.\n",
|
||||
"3. **Confirm the wallet and balance.** In the Privy reference frontend, verify that the wallet address matches the `WALLET_ADDRESS` printed in Step 7 above, and that the balance reflects the USDC you just funded via the Circle faucet. If the address or balance is wrong, you're logged in as a different user — log out and sign back in with the `LINKED_EMAIL` from `.env` before continuing.\n",
|
||||
"3. **Confirm the wallet and balance.** In the Privy reference frontend, verify that the wallet address matches the `WALLET_ADDRESS` printed in Step 7 above, and that the balance reflects the USDC funded via the Circle faucet. If the address or balance is wrong, you're logged in as a different user — log out and sign back in with the `LINKED_EMAIL` from `.env` before continuing.\n",
|
||||
"4. Choose **Connect agent → Give access**. This adds AgentCore as an *additional signer* on each of the user's Privy wallets.\n",
|
||||
"5. **This action grants signer access on every Privy wallet the user has.** If you ran this notebook with `NETWORK=SOLANA`, the Solana wallet was only just provisioned above — reload the Privy reference frontend in your browser so the page picks up the new wallet from Privy, then choose Connect agent once more.\n",
|
||||
"5. **This action grants signer access on every Privy wallet the user has.** If you ran this notebook with `NETWORK=SOLANA`, the Solana wallet was recently provisioned above — reload the Privy reference frontend in your browser so the page picks up the new wallet from Privy, then choose Connect agent once more.\n",
|
||||
"\n",
|
||||
"If the Privy reference frontend is not running, go back to `providers/stripe_privy_account_setup.ipynb` Step 6 and start it."
|
||||
]
|
||||
@@ -807,7 +799,7 @@
|
||||
"except Exception as e:\n",
|
||||
" print(f'⚠️ Balance check failed: {e}')\n",
|
||||
" print(' You can still proceed to Step 8 — the session creation will succeed even')\n",
|
||||
" print(' without a balance check. Ensure the wallet is funded as described in Step 7b.')\n"
|
||||
" print(' without a balance check. Verify the wallet is funded as described in Step 7b.')\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -896,7 +888,7 @@
|
||||
" 'logs:PutDeliveryDestination', 'logs:PutDeliverySource',\n",
|
||||
" 'logs:PutLogEvents', 'logs:PutResourcePolicy', 'logs:PutRetentionPolicy',\n",
|
||||
" ],\n",
|
||||
" 'Resource': '*',\n",
|
||||
" 'Resource': f'arn:aws:logs:{AWS_REGION}:{account_id}:log-group:/aws/vendedlogs/bedrock-agentcore/*',\n",
|
||||
" },\n",
|
||||
" {\n",
|
||||
" 'Sid': 'XRayApplicationSignalsCloudTrail',\n",
|
||||
@@ -908,7 +900,7 @@
|
||||
" 'application-signals:StartDiscovery',\n",
|
||||
" 'cloudtrail:CreateServiceLinkedChannel',\n",
|
||||
" ],\n",
|
||||
" 'Resource': '*',\n",
|
||||
" 'Resource': f'arn:aws:xray:{AWS_REGION}:{account_id}:*',\n",
|
||||
" },\n",
|
||||
" {\n",
|
||||
" 'Sid': 'CreateServiceLinkedRoleForAppSignals',\n",
|
||||
@@ -920,7 +912,7 @@
|
||||
" 'Sid': 'BedrockAgentCoreVendedLogDelivery',\n",
|
||||
" 'Effect': 'Allow',\n",
|
||||
" 'Action': 'bedrock-agentcore:AllowVendedLogDeliveryForResource',\n",
|
||||
" 'Resource': '*',\n",
|
||||
" 'Resource': f'arn:aws:bedrock-agentcore:{AWS_REGION}:{account_id}:*',\n",
|
||||
" },\n",
|
||||
" ],\n",
|
||||
" }\n",
|
||||
@@ -1006,7 +998,9 @@
|
||||
"4. Payment Manager (control plane)\n",
|
||||
"5. Credential Provider (control plane)\n",
|
||||
"\n",
|
||||
"Each step is idempotent — already-deleted resources are skipped gracefully."
|
||||
"Each step is idempotent — already-deleted resources are skipped gracefully.\n",
|
||||
"\n",
|
||||
"> **Cost notice:** After running cleanup, also delete the four IAM roles created by `setup_payment_roles()` from the IAM console and delete CloudWatch log groups (`/aws/vendedlogs/bedrock-agentcore/<manager-id>`) if observability was enabled. These are not removed by the cleanup cell and may incur ongoing costs."
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -1196,9 +1190,9 @@
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3 (ipykernel)",
|
||||
"display_name": "AgentCore Payments (.venv)",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
"name": "agentcore-payments"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
@@ -1210,7 +1204,7 @@
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.14.4"
|
||||
"version": "3.10.17"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
|
||||
+9
-2
@@ -9,7 +9,7 @@ This tutorial builds a payment-enabled agent that accesses paid x402 endpoints o
|
||||
| `strands_payment_agent.ipynb` | Strands Agents | `AgentCorePaymentsPlugin` (automatic, zero payment code) |
|
||||
| `langgraph_payment_agent.ipynb` | LangGraph | `wrap_with_auto_402()` using `PaymentManager.generate_payment_header()` |
|
||||
|
||||
The payment infrastructure (PaymentManager, sessions, instruments, payment limits) is identical in both. Only the agent framework integration differs.
|
||||
The payment infrastructure (PaymentManager, sessions, instruments, payment limits) is the same in both. Only the agent framework integration differs.
|
||||
|
||||
### What you'll learn
|
||||
|
||||
@@ -41,10 +41,17 @@ The payment infrastructure (PaymentManager, sessions, instruments, payment limit
|
||||
|
||||
Sessions are created fresh in each notebook — no stale session from `.env` needed.
|
||||
|
||||
This tutorial works with either wallet provider (Coinbase CDP or Stripe/Privy). The agent code is identical; only the `.env` values from Tutorial 00 differ.
|
||||
This tutorial works with either wallet provider (Coinbase CDP or Stripe/Privy). The agent code is the same; only the `.env` values from Tutorial 00 differ.
|
||||
|
||||
> **Testnet only.** All code uses Base Sepolia (Ethereum) with free USDC from [faucet.circle.com](https://faucet.circle.com/). Testnet USDC has no real-world value.
|
||||
|
||||
## Verification
|
||||
|
||||
After running the notebook, verify payment limits are enforced by:
|
||||
|
||||
1. Checking the session spend output shows amounts deducted after each x402 call.
|
||||
2. Confirming the overspend rejection message appears when the session budget is exhausted.
|
||||
|
||||
## Cleanup
|
||||
|
||||
Payment sessions expire automatically after their configured `expiryTimeInMinutes`. To delete all payment resources (Manager, Connector, Instrument), run the cleanup cell in Tutorial 00 after completing experimentation with all notebooks.
|
||||
|
||||
+27
-20
@@ -8,7 +8,7 @@
|
||||
"\n",
|
||||
"## Overview\n",
|
||||
"\n",
|
||||
"This tutorial shows how to build a payment-enabled AI agent using **LangGraph** and **AgentCore payments**. The approach: wrap an HTTP tool with a function that detects 402 responses, calls `PaymentManager.generate_payment_header()`, and retries. The LLM never sees the 402.\n",
|
||||
"This tutorial shows how to build a payment-enabled AI agent using **LangGraph** and **AgentCore payments**. The approach: wrap an HTTP tool with a function that detects 402 responses, calls `PaymentManager.generate_payment_header()`, and retries. The LLM does not see the 402.\n",
|
||||
"\n",
|
||||
"```\n",
|
||||
"LangGraph ReAct Agent\n",
|
||||
@@ -19,7 +19,7 @@
|
||||
" └── Returns content to agent\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"> **Testnet only.** All code uses Base Sepolia or Solana Devnet with free USDC from [faucet.circle.com](https://faucet.circle.com/). Testnet USDC has no real-world value."
|
||||
"> **Testnet only.** All code uses Base Sepolia or Solana Devnet with free USDC from [faucet.circle.com](https://faucet.circle.com/). Testnet USDC has no real-world value.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -41,7 +41,7 @@
|
||||
"* Wallet funded with testnet USDC\n",
|
||||
"* `pip install langchain-aws langgraph bedrock-agentcore pydantic requests python-dotenv`\n",
|
||||
"\n",
|
||||
"This tutorial works with any wallet provider you configured in Tutorial 00 - Coinbase CDP or Stripe (Privy)."
|
||||
"This tutorial works with either wallet provider you configured in Tutorial 00 - Coinbase CDP or Stripe (Privy)."
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -149,9 +149,9 @@
|
||||
"source": [
|
||||
"## Step 3 — Build the Auto-402 Tool Wrapper\n",
|
||||
"\n",
|
||||
"The `wrap_with_auto_402()` function wraps any LangGraph tool to handle 402 responses transparently. The raw HTTP tool returns `{statusCode, headers, body}` — the wrapper checks for 402, calls `PaymentManager.generate_payment_header()`, and retries with the payment proof. The LLM never sees the 402.\n",
|
||||
"The `wrap_with_auto_402()` function wraps any LangGraph tool to handle 402 responses transparently. The raw HTTP tool returns `{statusCode, headers, body}` — the wrapper checks for 402, calls `PaymentManager.generate_payment_header()`, and retries with the payment proof. The LLM does not see the 402.\n",
|
||||
"\n",
|
||||
"This pattern works with any tool that returns HTTP-like responses — not just `http_request`."
|
||||
"This pattern works with any tool that returns HTTP-like responses — not just `http_request`.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -181,7 +181,7 @@
|
||||
"def wrap_with_auto_402(tool, manager, user_id, instrument_id, session_id, network_prefs=None):\n",
|
||||
" \"\"\"Wrap a tool to auto-handle x402 Payment Required responses.\n",
|
||||
"\n",
|
||||
" The LLM never sees the 402 — the wrapper intercepts it, signs the payment\n",
|
||||
" The LLM does not see the 402 — the wrapper intercepts it, signs the payment\n",
|
||||
" via PaymentManager.generate_payment_header(), and retries with the proof.\n",
|
||||
" \"\"\"\n",
|
||||
" original = tool.func\n",
|
||||
@@ -256,7 +256,7 @@
|
||||
"# Wrap with auto-402 handling (including network preferences)\n",
|
||||
"wrapped_http = wrap_with_auto_402(http_tool, payment_manager, USER_ID, INSTRUMENT_ID, SESSION_ID, NETWORK_PREFS)\n",
|
||||
"\n",
|
||||
"print('✅ http_request tool with x402 auto-payment handling')"
|
||||
"print('✅ http_request tool with x402 auto-payment handling')\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -265,7 +265,7 @@
|
||||
"source": [
|
||||
"## Step 4 — Create the LangGraph Agent\n",
|
||||
"\n",
|
||||
"Using `create_agent` from `langchain.agents` to build a ReAct agent with our payment-wrapped tool."
|
||||
"Use `create_agent` from `langchain.agents` to build a ReAct agent with the payment-wrapped tool."
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -295,7 +295,7 @@
|
||||
"source": [
|
||||
"## Step 5 — Run the Agent\n",
|
||||
"\n",
|
||||
"We use `agent.stream()` with `stream_mode=\"messages\"` to stream the agent response token-by-token via the Converse API. After streaming completes, we display the full tool response separately so you can inspect what the paid API returned."
|
||||
"Use `agent.stream()` with `stream_mode=\"messages\"` to stream the agent response token-by-token via the Converse API. After streaming completes, the full tool response is displayed separately so you can inspect what the paid API returned."
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -347,7 +347,7 @@
|
||||
"source": [
|
||||
"## Step 6 — Payment Limits\n",
|
||||
"\n",
|
||||
"The session budget is how you control agent spending. Let's see how it works.\n",
|
||||
"The session budget is how you control agent spending. The cells below demonstrate how it works.\n",
|
||||
"\n",
|
||||
"### How payment limits work\n",
|
||||
"\n",
|
||||
@@ -448,10 +448,10 @@
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### 6b — Budget exceeded: the agent cannot overspend\n",
|
||||
"### 6b — Budget exceeded: the budget is enforced at the infrastructure level\n",
|
||||
"\n",
|
||||
"Create a session with a tiny budget ($0.0001) — less than the $0.001 cost of the weather API.\n",
|
||||
"The service rejects the payment. No prompt injection or agent misbehavior can bypass this."
|
||||
"The service rejects the payment. This is enforced at the infrastructure level by AgentCore payments.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -501,15 +501,15 @@
|
||||
"except Exception as e:\n",
|
||||
" print(f'\\n\\n💰 Budget exceeded — payment rejected by the service:')\n",
|
||||
" print(f' {e}')\n",
|
||||
" print(f'\\n This is the expected behavior. The agent cannot overspend.')\n",
|
||||
" print(f' Budget enforcement is at the infrastructure level, not application code.')"
|
||||
" print(f'\\n This is the expected behavior. The budget is enforced at the infrastructure level.')\n",
|
||||
" print(f' Budget enforcement is at the infrastructure level, not application code.')\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"The agent attempted the payment, but the service rejected it because the transaction amount ($0.001) exceeds the session budget ($0.0001). This is enforced by AgentCore payments infrastructure — no amount of prompt injection or agent misbehavior can bypass it."
|
||||
"The agent attempted the payment, but the service rejected it because the transaction amount ($0.001) exceeds the session budget ($0.0001). This is enforced at the infrastructure level by AgentCore payments.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -566,12 +566,19 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "verification-langgraph",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Cleanup\n",
|
||||
"## Verification\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"To delete all payment resources (Manager, Connector, Instrument), run the cleanup cell in Tutorial 00 (`setup_agentcore_payments.ipynb`)."
|
||||
"If the cells above ran without errors, your LangGraph payment agent made a successful payment. You should see a 200 response from the API above and a reduced `availableLimit` in the session budget check — confirming the payment was authorized and tracked by AgentCore."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Cleanup\n\n\nPayment sessions created in this tutorial expire automatically after their configured `expiryTimeInMinutes`. No manual deletion needed.\n\nTo delete all payment resources (Manager, Connector, Instrument), run the cleanup cell in Tutorial 00 (`setup_agentcore_payments.ipynb`)."
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -592,13 +599,13 @@
|
||||
"\n",
|
||||
"## Conclusion\n",
|
||||
"\n",
|
||||
"Payment limits are enforced at the infrastructure level — the agent cannot overspend regardless of LLM behavior.\n",
|
||||
"Payment limits are enforced at the infrastructure level — the service is designed to prevent overspending regardless of LLM behavior.\n",
|
||||
"\n",
|
||||
"### Next Steps\n",
|
||||
"\n",
|
||||
"* **Tutorial 02** — Deploy this agent to AgentCore Runtime with proper role separation\n",
|
||||
"* **Tutorial 03** — Wallet operations: delegation, funding, balance checks\n",
|
||||
"* **Tutorial 04** — Discover and call paid MCP tools on Coinbase Bazaar through AgentCore Gateway"
|
||||
"* **Tutorial 04** — Discover and call paid MCP tools on Coinbase Bazaar through AgentCore Gateway\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
+45
-21
@@ -72,7 +72,10 @@
|
||||
"* Wallet funded with testnet USDC from https://faucet.circle.com/\n",
|
||||
"* `pip install 'bedrock-agentcore[strands-agents]'`\n",
|
||||
"\n",
|
||||
"This notebook works with either wallet provider — Coinbase CDP or Stripe (Privy). The agent code is identical; only the `.env` values from Tutorial 00 differ.\n"
|
||||
"This notebook works with either wallet provider — Coinbase CDP or Stripe (Privy). The agent code is the same; only the `.env` values from Tutorial 00 differ.\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"> **Cost notice:** This tutorial uses testnet USDC (no real-world value) but the underlying AWS resources (AgentCore payments) may incur charges."
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -81,7 +84,7 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"!pip install -r requirements.txt --quiet"
|
||||
"%pip install -r requirements.txt --quiet"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -90,7 +93,7 @@
|
||||
"source": [
|
||||
"## Verify AWS Credentials\n",
|
||||
"\n",
|
||||
"Ensure your AWS credentials are configured before proceeding. You can use any standard method:\n",
|
||||
"Verify your AWS credentials are configured before proceeding. You can use any standard method:\n",
|
||||
"- `aws configure` (access keys)\n",
|
||||
"- `aws sso login --profile <your-profile>` (SSO)\n",
|
||||
"- Environment variables (`AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`)\n",
|
||||
@@ -108,6 +111,7 @@
|
||||
"\n",
|
||||
"# Uncomment the next line to use a named AWS profile:\n",
|
||||
"#os.environ['AWS_PROFILE'] = '<your-profile>'\n",
|
||||
"AWS_REGION = \"us-west-2\"\n",
|
||||
"\n",
|
||||
"session = boto3.Session()\n",
|
||||
"identity = session.client('sts').get_caller_identity()\n",
|
||||
@@ -121,7 +125,7 @@
|
||||
"source": [
|
||||
"## Step 1: Load Config from .env\n",
|
||||
"\n",
|
||||
"Tutorial 00 wrote resource IDs into `.env`. We load them with `load_dotenv()` — the standard Python pattern. The agent code below is identical regardless of which wallet provider you configured.\n"
|
||||
"Tutorial 00 wrote resource IDs into `.env`. We load them with `load_dotenv()` — the standard Python pattern. The agent code below is the same regardless of which wallet provider you configured.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -179,9 +183,9 @@
|
||||
"2. **Call** `ProcessPayment` via AgentCore to sign the transaction and generate a proof\n",
|
||||
"3. **Retry** the original request with the payment proof attached\n",
|
||||
"\n",
|
||||
"All of this happens inside the agent loop — the LLM never sees payment details or makes payment decisions.\n",
|
||||
"All of this happens inside the agent loop — the LLM does not see payment details or make payment decisions.\n",
|
||||
"\n",
|
||||
"All payments use **USDC stablecoin** (1 USDC = $1.00 USD) — no volatility, near-zero transaction fees, instant settlement."
|
||||
"All payments use **USDC stablecoin** (1 USDC = $1.00 USD) — no volatility, near-zero transaction fees, instant settlement.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -231,7 +235,7 @@
|
||||
"\n",
|
||||
"Attach the payment plugin to a Strands agent. The agent gets payment capability with one line: `plugins=[payment_plugin]`.\n",
|
||||
"\n",
|
||||
"When any tool returns a 402 response, the plugin handles payment automatically — the agent and the LLM never touch wallet credentials or payment logic."
|
||||
"When any tool returns a 402 response, the plugin handles payment automatically — the agent and the LLM do not touch wallet credentials or payment logic.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -424,7 +428,7 @@
|
||||
"source": [
|
||||
"### What happens when the budget is exceeded?\n",
|
||||
"\n",
|
||||
"Let's create a session with a tiny budget ($0.0001) and see what happens when the agent tries to pay for something that costs more ($0.001). The service rejects the payment — the agent cannot overspend."
|
||||
"Let's create a session with a tiny budget ($0.0001) and see what happens when the agent tries to pay for something that costs more ($0.001). The service rejects the payment — the budget is enforced at the infrastructure level.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -479,15 +483,15 @@
|
||||
"except Exception as e:\n",
|
||||
" print(f'💰 Budget exceeded — payment rejected by the service:')\n",
|
||||
" print(f' {e}')\n",
|
||||
" print(f'\\n This is the expected behavior. The agent cannot overspend.')\n",
|
||||
" print(f' The budget is enforced by AgentCore payments, not by application code.')"
|
||||
" print(f'\\n This is the expected behavior. The budget is enforced at the infrastructure level.')\n",
|
||||
" print(f' The budget is enforced by AgentCore payments, not by application code.')\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"The agent tried to pay, but the service rejected it because the payment amount exceeded the $0.0001 session budget. This is enforced at the infrastructure level — no amount of prompt injection or agent misbehavior can bypass it."
|
||||
"The agent tried to pay, but the service rejected it because the payment amount exceeded the $0.0001 session budget. This is enforced at the infrastructure level by AgentCore payments.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -621,9 +625,9 @@
|
||||
"source": [
|
||||
"## Step 6: View payment traces in AgentCore Observability\n",
|
||||
"\n",
|
||||
"Every `ProcessPayment` call from the agent produced a trace. Open the Amazon CloudWatch console to see the payment flow.\n",
|
||||
"Every `ProcessPayment` call from the agent produced a trace. Open the CloudWatch console to see the payment flow.\n",
|
||||
"\n",
|
||||
"1. Open the [Amazon CloudWatch console](https://console.aws.amazon.com/cloudwatch/)\n",
|
||||
"1. Open the [CloudWatch console](https://console.aws.amazon.com/cloudwatch/)\n",
|
||||
"2. In the left navigation, choose **X-Ray traces** > **Traces**\n",
|
||||
"3. Filter by service name `bedrock-agentcore`\n",
|
||||
"4. Select a trace to see the three-phase payment flow: reserve budget, sign transaction, commit\n",
|
||||
@@ -662,7 +666,27 @@
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": "## The wallet-agnostic, network-agnostic story\n\nThe agent code above is **identical** regardless of:\n- **Which wallet provider** — Coinbase CDP or Stripe Privy\n- **Which blockchain network** — Ethereum (Base Sepolia) or Solana (Solana Devnet)\n\nThe only thing that changes is the `INSTRUMENT_ID` and `PAYMENT_CONNECTOR_ID` in your `.env` — which Tutorial 00 set for you. The plugin handles the rest.\n\n### Why this works\n\n| Layer | Network-aware? | What it knows |\n|-------|---------------|---------------|\n| PaymentManager | No | Authorization policy only |\n| PaymentConnector | No | Which provider (Coinbase/Privy), not which chain |\n| PaymentInstrument | **Yes** | `network: ETHEREUM` or `network: SOLANA` — set at creation |\n| ProcessPayment | **Yes** | Merchant's 402 payload specifies the chain (`eip155:84532` or `solana:...`) |\n| Agent code | **No** | Passes the instrument ID to the plugin |\n\nThe control plane (manager, connector, credentials) is set up once and works across all networks. To switch networks, you create a new instrument — one data plane API call. No control plane changes."
|
||||
"source": [
|
||||
"## The wallet-agnostic, network-agnostic story\n",
|
||||
"\n",
|
||||
"The agent code above does not change based on:\n",
|
||||
"- **Which wallet provider** — Coinbase CDP or Stripe Privy\n",
|
||||
"- **Which blockchain network** — Ethereum (Base Sepolia) or Solana (Solana Devnet)\n",
|
||||
"\n",
|
||||
"The only thing that changes is the `INSTRUMENT_ID` and `PAYMENT_CONNECTOR_ID` in your `.env` — which Tutorial 00 set for you. The plugin handles the rest.\n",
|
||||
"\n",
|
||||
"### Why this works\n",
|
||||
"\n",
|
||||
"| Layer | Network-aware? | What it knows |\n",
|
||||
"|-------|---------------|---------------|\n",
|
||||
"| PaymentManager | No | Authorization policy only |\n",
|
||||
"| PaymentConnector | No | Which provider (Coinbase/Privy), not which chain |\n",
|
||||
"| PaymentInstrument | **Yes** | `network: ETHEREUM` or `network: SOLANA` — set at creation |\n",
|
||||
"| ProcessPayment | **Yes** | Merchant's 402 payload specifies the chain (`eip155:84532` or `solana:...`) |\n",
|
||||
"| Agent code | **No** | Passes the instrument ID to the plugin |\n",
|
||||
"\n",
|
||||
"The control plane (manager, connector, credentials) is set up once and works across all networks. To switch networks, you create a new instrument — one data plane API call. No control plane changes."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
@@ -731,7 +755,7 @@
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## What Just Happened\n",
|
||||
"## What Happened\n",
|
||||
"\n",
|
||||
"In about 10 lines of code, you:\n",
|
||||
"\n",
|
||||
@@ -741,13 +765,13 @@
|
||||
"4. Ran the agent — it paid for content automatically\n",
|
||||
"5. Created a budget-constrained session and verified spend tracking\n",
|
||||
"\n",
|
||||
"The agent never saw wallet credentials. The LLM never made payment decisions. The budget was enforced by the service, not by application code.\n",
|
||||
"The agent did not see wallet credentials. The LLM did not make payment decisions. The budget was enforced by the service, not by application code.\n",
|
||||
"\n",
|
||||
"### Next Steps\n",
|
||||
"\n",
|
||||
"* **Tutorial 02** — Deploy this agent to AgentCore Runtime with proper role separation using the AgentCore CLI\n",
|
||||
"* **Tutorial 03** — Wallet operations: delegation, funding, balance checks, multi-session patterns\n",
|
||||
"* **Tutorial 04** — Discover and call paid MCP tools on Coinbase Bazaar through AgentCore Gateway"
|
||||
"* **Tutorial 04** — Discover and call paid MCP tools on Coinbase Bazaar through AgentCore Gateway\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -769,9 +793,9 @@
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3 (ipykernel)",
|
||||
"display_name": "AgentCore Payments (.venv)",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
"name": "agentcore-payments"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
@@ -783,9 +807,9 @@
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.14.4"
|
||||
"version": "3.10.17"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 4
|
||||
}
|
||||
}
|
||||
|
||||
+5
-1
@@ -38,7 +38,7 @@ The agent code is stateless and wallet-agnostic. All payment context (manager AR
|
||||
* [AWS CDK](https://docs.aws.amazon.com/cdk/v2/guide/getting_started.html) installed
|
||||
* AWS CLI configured (`aws configure`)
|
||||
|
||||
This tutorial works with either wallet provider - Coinbase CDP or Stripe (Privy). The agent code is identical; only the `.env` values from Tutorial 00 differ.
|
||||
This tutorial works with either wallet provider - Coinbase CDP or Stripe (Privy). The agent code is the same; only the `.env` values from Tutorial 00 differ.
|
||||
|
||||
> **Testnet only.** All code uses Base Sepolia with free USDC from [faucet.circle.com](https://faucet.circle.com/). Testnet USDC has no real-world value.
|
||||
|
||||
@@ -113,6 +113,8 @@ agentcore remove all -y
|
||||
|
||||
## Cleanup
|
||||
|
||||
> **Cost notice:** AgentCore Runtime deployments, payment sessions, and CloudWatch observability incur AWS charges.
|
||||
|
||||
AgentCore Runtime deployments incur charges for compute and storage. Remove when done:
|
||||
|
||||
```bash
|
||||
@@ -121,6 +123,8 @@ cd PaymentAgent && agentcore remove all -y
|
||||
|
||||
This removes the Runtime deployment, CloudWatch log groups, and associated resources.
|
||||
|
||||
**Payment sessions** — The sessions created in this tutorial expire automatically after their configured `expiryTimeInMinutes` (60 minutes). No manual cleanup needed.
|
||||
|
||||
## Conclusion
|
||||
|
||||
This tutorial deploys a payment-enabled Strands agent to AgentCore Runtime with proper role separation. The deployed agent runs under ProcessPaymentRole and can only spend within budgets set by the app backend (ManagementRole).
|
||||
|
||||
+47
-9
@@ -2,13 +2,14 @@
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "b032a5c7",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Deploy Payment Agent to AgentCore Runtime\n",
|
||||
"\n",
|
||||
"## Overview\n",
|
||||
"\n",
|
||||
"In Tutorial 01, we ran a payment-enabled agent locally in a notebook. This tutorial deploys the same agent to\n",
|
||||
"Tutorial 01 ran a payment-enabled agent locally in a notebook. This tutorial deploys the same agent to\n",
|
||||
"**AgentCore Runtime** so it can be invoked over HTTPS with SigV4 auth.\n",
|
||||
"\n",
|
||||
"The deployed agent runs under a dedicated execution role. The **AgentCorePaymentsPlugin**\n",
|
||||
@@ -45,6 +46,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "ad2b9e9f",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### High-Level Architecture\n",
|
||||
@@ -54,6 +56,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "5d5ce243",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Prerequisites\n",
|
||||
@@ -69,6 +72,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "16732ea7",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Step 1: Install the AgentCore CLI\n",
|
||||
@@ -79,6 +83,7 @@
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "6a40c736",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
@@ -88,6 +93,7 @@
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "3a6f4cb4",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
@@ -96,6 +102,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "fcd1647e",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Step 2: Install Python Dependencies\n",
|
||||
@@ -106,14 +113,16 @@
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "2b93e109",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"!pip install -r requirements.txt --quiet"
|
||||
"%pip install -r requirements.txt --quiet"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "f2a79c2e",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Step 3: Verify AWS Credentials\n",
|
||||
@@ -124,6 +133,7 @@
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "393df7b2",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
@@ -143,6 +153,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "224d6073",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Step 4: Load Payment Config\n",
|
||||
@@ -155,6 +166,7 @@
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "40d6ee93",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
@@ -212,6 +224,7 @@
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "cb2b0821",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
@@ -245,6 +258,7 @@
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "45779f42",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
@@ -277,6 +291,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "9ada46f8",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Local test passed. Stop the agent (`Ctrl+C` in the terminal) and proceed to cloud deployment."
|
||||
@@ -284,16 +299,18 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "e1c6f581",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Step 6: Scaffold the AgentCore Project\n",
|
||||
"\n",
|
||||
"`agentcore create` generates the project structure that the CLI needs for deployment (CDK infra, config files, app directory). We then copy our payment agent code and vendored wheels into it."
|
||||
"`agentcore create` generates the project structure that the CLI needs for deployment (CDK infra, config files, app directory). Then copy the payment agent code and vendored wheels into it."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "76e21931",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
@@ -309,6 +326,7 @@
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "e92536a1",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
@@ -352,11 +370,12 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "f92c0a13",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Step 7: Deploy to AgentCore Runtime\n",
|
||||
"\n",
|
||||
"The CLI auto-creates an execution role with Bedrock model + observability permissions. After deploy, we add payment permissions to that role.\n",
|
||||
"The CLI auto-creates an execution role with Bedrock model + observability permissions. After deploy, add payment permissions to that role.\n",
|
||||
"\n",
|
||||
"First deploy takes ~2-3 minutes."
|
||||
]
|
||||
@@ -372,6 +391,7 @@
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "25ef81fa",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
@@ -381,6 +401,7 @@
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "1be6284f",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
@@ -390,16 +411,18 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "474f148b",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Add payment permissions to the auto-created execution role\n",
|
||||
"\n",
|
||||
"The CLI created a role with Bedrock + CloudWatch permissions. We add payment data-plane permissions so the plugin can call `ProcessPayment`."
|
||||
"The CLI created a role with Bedrock + CloudWatch permissions. Add payment data-plane permissions so the plugin can call `ProcessPayment`."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "893853cd",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
@@ -466,6 +489,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "497c9125",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Step 8: Invoke the Deployed Agent\n",
|
||||
@@ -475,6 +499,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "91c37322",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Payment Flow Sequence\n",
|
||||
@@ -485,6 +510,7 @@
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "1fed0763",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
@@ -501,6 +527,7 @@
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "a7e720bb",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
@@ -519,6 +546,7 @@
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "fcc2d727",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
@@ -528,6 +556,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "20fb3b85",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Step 9: Verify Session Spend\n",
|
||||
@@ -538,6 +567,7 @@
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "7c8a3d78",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
@@ -559,6 +589,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "48143de9",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Observability\n",
|
||||
@@ -569,6 +600,7 @@
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "04d3a27f",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
@@ -586,16 +618,20 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "e986849a",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Cleanup\n",
|
||||
"\n",
|
||||
"Remove the deployed Runtime and associated AWS resources."
|
||||
"Remove the deployed Runtime and associated AWS resources.\n",
|
||||
"\n",
|
||||
"**Payment sessions** — The sessions created in this tutorial expire automatically after 60 minutes. No manual cleanup needed."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "f35341d8",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
@@ -606,6 +642,7 @@
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "c6491829",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
@@ -620,6 +657,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "50f53f9c",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Summary\n",
|
||||
@@ -638,7 +676,7 @@
|
||||
"- Receives all payment context in the invocation payload (stateless)\n",
|
||||
"- Plugin handles 402 → ProcessPayment automatically\n",
|
||||
"- Cannot exceed the session budget (enforced server-side)\n",
|
||||
"- Works with any wallet provider configured in Tutorial 00\n",
|
||||
"- Works with either supported wallet provider configured in Tutorial 00\n",
|
||||
"\n",
|
||||
"### Next: Tutorial 03 — User Onboarding & Wallet Funding"
|
||||
]
|
||||
@@ -646,7 +684,7 @@
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": ".venv",
|
||||
"display_name": "Python 3 (ipykernel)",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
@@ -660,7 +698,7 @@
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.12.11"
|
||||
"version": "3.14.4"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
|
||||
+1
-1
@@ -32,7 +32,7 @@ This tutorial works with either wallet provider you configured in Tutorial 00 (C
|
||||
|
||||
## Cleanup
|
||||
|
||||
Payment instruments persist until explicitly deleted. Sessions expire automatically. To delete all payment resources, run the cleanup cell in Tutorial 00.
|
||||
Payment instruments persist until explicitly deleted. The three payment sessions created in this tutorial (quick lookup, research task, deep analysis) expire automatically after their configured `expiryTimeInMinutes`. To delete all payment resources (Manager, Connectors, Instruments), run the cleanup cell in Tutorial 00.
|
||||
|
||||
## Conclusion
|
||||
|
||||
|
||||
+24
-10
@@ -20,7 +20,7 @@
|
||||
"\n",
|
||||
"## Prerequisites\n",
|
||||
"\n",
|
||||
"> **Cost notice:** Payment Instruments may incur AWS charges while provisioned. This tutorial uses testnet resources but the AWS infrastructure is billable. Run Tutorial 00's cleanup when finished.\n",
|
||||
"> **Cost notice:** Please see AgentCore pricing for more details on cost for the services used - https://aws.amazon.com/bedrock/agentcore/pricing/. This tutorial uses testnet resources but the AWS infrastructure is billable. Run Tutorial 00's cleanup when finished.\n",
|
||||
"\n",
|
||||
"* Tutorial 00 completed (`.env` exists with `PAYMENT_MANAGER_ARN`, `PAYMENT_CONNECTOR_ID`, `LINKED_EMAIL`)\n",
|
||||
"* Testnet USDC from https://faucet.circle.com/ (Base Sepolia or Solana Devnet)"
|
||||
@@ -33,7 +33,7 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"!pip install -r requirements.txt --quiet"
|
||||
"%pip install -r requirements.txt --quiet"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -83,7 +83,7 @@
|
||||
"id": "tut03-persona-callout",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"> **Two personas in this tutorial.** The cells below simulate both sides of the lifecycle — your *application backend* (provisions the wallet, runs balance and session operations) and the *end user* (funds the wallet, grants consent through a UI). For simplicity we reuse the developer email (`LINKED_EMAIL` from `.env`) as the end-user identity. In production each of your users would have their own email and their own wallet.\n"
|
||||
"> **Two personas in this tutorial.** The cells below simulate both sides of the lifecycle — your *application backend* (provisions the wallet, runs balance and session operations) and the *end user* (funds the wallet, grants consent through a UI). For simplicity, the tutorial reuses the developer email (`LINKED_EMAIL` from `.env`) as the end-user identity. In production each of your users would have their own email and their own wallet.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -115,9 +115,9 @@
|
||||
"source": [
|
||||
"## 1. Create an Embedded Wallet\n",
|
||||
"\n",
|
||||
"This is the core onboarding call. Your application backend runs `CreatePaymentInstrument` every time a user signs up — it provisions an embedded USDC wallet linked to the user's identity (email, phone, or OAuth). The user never sees a private key; the wallet provider (Coinbase or Privy) holds key material on their behalf.\n",
|
||||
"This is the core onboarding call. Your application backend runs `CreatePaymentInstrument` every time a user signs up — it provisions an embedded USDC wallet linked to the user's identity (email, phone, or OAuth). The user does not see a private key; the wallet provider (Coinbase or Privy) holds key material on their behalf.\n",
|
||||
"\n",
|
||||
"Tutorial 00 did this for the developer's wallet. Here we onboard a second user so you see the call run end-to-end.\n",
|
||||
"Tutorial 00 did this for the developer's wallet. This cell onboards a second user so you see the call run end-to-end.\n",
|
||||
"\n",
|
||||
"> **Email reuse for this tutorial.** The code cell below reads `LINKED_EMAIL` from your `.env` — the same email you set up in Tutorial 00 — so the \"new user\" is really you wearing a different hat. Keeping one email keeps the tutorial simple (one inbox, one set of OTP codes, one wallet login). In a signup flow you would pass the actual new user's email here.\n"
|
||||
]
|
||||
@@ -246,7 +246,11 @@
|
||||
"|---|---|---|\n",
|
||||
"| **Mechanism** | Project-level delegated signing | Authorization key as an additional signer on the wallet |\n",
|
||||
"| **Setup** | CDP Portal → Wallets → Embedded Wallet → Policies → enable | Privy reference frontend `addSigners()` call |\n",
|
||||
"| **User action** | Grant consent via WalletHub `redirectUrl` | Log in at `http://localhost:3000` with the end-user email and choose **Connect agent → Give access**. Same UI as Section 2's Add funds. |\n",
|
||||
"| **User action** | Grant consent via WalletHub `redirectUrl` | 1. Log in at `http://localhost:3000` with the end-user email.\n",
|
||||
"2. Choose **Connect agent**.\n",
|
||||
"3. Choose **Give access**.\n",
|
||||
"\n",
|
||||
"Same UI as Section 2's Add funds. |\n",
|
||||
"| **Scope** | All wallets under the project | Per-wallet |\n",
|
||||
"| **Without it** | ProcessPayment fails with error | ProcessPayment returns HTTP 500 |\n",
|
||||
"\n",
|
||||
@@ -274,7 +278,7 @@
|
||||
"\n",
|
||||
"The remaining sections run from your application backend, not by the end user. They cover the ops you call before, during, and after an agent task: balance checks, adding wallets on additional chains, session budgets, instrument listings, and remaining-budget queries. Each section is marked with a 🖥️ callout so the persona boundary stays obvious as you read.\n",
|
||||
"\n",
|
||||
"We reuse the user onboarded in Section 1 so these calls run against a real wallet.\n"
|
||||
"The cells below reuse the user onboarded in Section 1 so these calls run against a real wallet.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -415,7 +419,7 @@
|
||||
"\n",
|
||||
"> **🖥️ Backend operation.** `ListPaymentInstruments` is a backend call, typically used by ops tooling, support dashboards, or a wallet-selector UI your application renders for the user.\n",
|
||||
"\n",
|
||||
"See all wallets for a given user. Useful for building a wallet selection UI, account dashboards, or support tools. The call is scoped per user, so we list instruments for both users we created across Tutorial 00 and Section 1.\n",
|
||||
"See all wallets for a given user. Useful for building a wallet selection UI, account dashboards, or support tools. The call is scoped per user. The cell below lists instruments for both users created across Tutorial 00 and Section 1.\n",
|
||||
"\n",
|
||||
"`ListPaymentInstruments` returns a lightweight summary (ID, type, status, timestamps) — not the full wallet details. If you need the network or wallet address for a given instrument, call `GetPaymentInstrument` with its `paymentInstrumentId`."
|
||||
]
|
||||
@@ -456,7 +460,7 @@
|
||||
"\n",
|
||||
"> **🖥️ Backend operation.** `GetPaymentSession` is a backend call. Your application queries it to surface remaining budget to the user, decide whether to route more work to the agent, or log spend.\n",
|
||||
"\n",
|
||||
"`GetPaymentSession` returns `availableLimits.availableSpendAmount` — the remaining budget in real time. Call this from your backend to show the user how much they have left before routing more work to the agent. We inspect all three sessions we created in Section 6 so you can see the shape in context."
|
||||
"`GetPaymentSession` returns `availableLimits.availableSpendAmount` — the remaining budget in real time. Call this from your backend to show the user how much they have left before routing more work to the agent. The cell below inspects all three sessions created in Section 6 so you can see the shape in context."
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -521,6 +525,16 @@
|
||||
"| SOLANA | Solana Devnet | `solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1` | faucet.circle.com → Solana Devnet |\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "verification-onboarding",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Verification\n",
|
||||
"\n",
|
||||
"If the cells above ran without errors, your wallet operations succeeded. You should see wallet addresses printed for each instrument and a non-zero USDC balance returned by `GetPaymentInstrumentBalance` — confirming the wallet was created, funded, and is accessible by the backend."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "d6f38cd7",
|
||||
@@ -528,7 +542,7 @@
|
||||
"source": [
|
||||
"## Cleanup\n",
|
||||
"\n",
|
||||
"Sessions expire automatically. To delete all payment resources, run the cleanup cell in Tutorial 00.\n",
|
||||
"The three payment sessions created in this tutorial (quick lookup, research task, deep analysis) expire automatically after their configured `expiryTimeInMinutes`. To delete all payment resources, run the cleanup cell in Tutorial 00.\n",
|
||||
"\n",
|
||||
"The Instrument created in this notebook (`NEW_INSTRUMENT_ID`) is cleaned up when you delete the Payment Manager in Tutorial 00."
|
||||
]
|
||||
|
||||
+4
-2
@@ -64,7 +64,7 @@ The Coinbase x402 Bazaar is an MCP marketplace exposing 10,000+ pay-per-use x402
|
||||
* AgentCore CLI: `npm install -g @aws/agentcore` (requires Node.js 20+)
|
||||
* AWS CLI configured (`aws configure`)
|
||||
|
||||
This tutorial works with either wallet provider you configured in Tutorial 00 (Coinbase CDP or Stripe/Privy). The agent code is identical regardless of your choice.
|
||||
This tutorial works with either wallet provider you configured in Tutorial 00 (Coinbase CDP or Stripe/Privy). The agent code is the same regardless of your choice.
|
||||
|
||||
> **Testnet only.** All code uses Base Sepolia (Ethereum) with free USDC from [faucet.circle.com](https://faucet.circle.com/). Testnet USDC has no real-world value.
|
||||
|
||||
@@ -96,7 +96,9 @@ Add the `GATEWAY_URL` from the output to your `.env` file.
|
||||
|
||||
## Cleanup
|
||||
|
||||
AgentCore Gateway incurs charges for requests and data transfer. Remove when done:
|
||||
> **Cost notice:** AgentCore Gateway incurs AWS charges for requests and data transfer. Run cleanup when finished to avoid ongoing costs.
|
||||
|
||||
Remove the Gateway when done:
|
||||
|
||||
```bash
|
||||
agentcore remove gateway --name BazaarGateway -y
|
||||
|
||||
+83
-83
@@ -9,48 +9,48 @@
|
||||
"\n",
|
||||
"## Overview\n",
|
||||
"\n",
|
||||
"The **Coinbase x402 Bazaar** is an MCP marketplace where paid tools are listed with semantic descriptions, pricing, and input/output schemas. Agents discover tools via `search_resources` and call them via `proxy_tool_call` \u2014 the Bazaar handles 402 detection and payment routing.\n",
|
||||
"The **Coinbase x402 Bazaar** is an MCP marketplace where paid tools are listed with semantic descriptions, pricing, and input/output schemas. Agents discover tools via `search_resources` and call them via `proxy_tool_call` — the Bazaar handles 402 detection and payment routing.\n",
|
||||
"\n",
|
||||
"In this tutorial, we connect the Bazaar to an **AgentCore Gateway** as a native MCP target, then build a Strands agent that discovers and calls paid tools with automatic payment handling.\n",
|
||||
"\n",
|
||||
"### How It Works\n",
|
||||
"\n",
|
||||
"```\n",
|
||||
"\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n",
|
||||
"\u2502 \ud83e\uddd1\u200d\ud83d\udcbb Developer Code \u2502\n",
|
||||
"\u2502 \u2502\n",
|
||||
"\u2502 Strands Agent \u2502\n",
|
||||
"\u2502 + AgentCorePaymentsPlugin \u2502\n",
|
||||
"\u2502 + MCPClient (streamable HTTP) \u2502\n",
|
||||
"\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n",
|
||||
" \u2502 MCP protocol\n",
|
||||
"\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u25bc\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n",
|
||||
"\u2502 \ud83d\udd00 AgentCore Gateway \u2502\n",
|
||||
"\u2502 Target: Coinbase x402 Bazaar \u2502\n",
|
||||
"\u2502 (No outbound auth) \u2502\n",
|
||||
"\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n",
|
||||
" \u2502\n",
|
||||
"\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u25bc\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n",
|
||||
"\u2502 \ud83c\udf10 Coinbase x402 Bazaar \u2502\n",
|
||||
"\u2502 search_resources \u2192 discover \u2502\n",
|
||||
"\u2502 proxy_tool_call \u2192 call + pay \u2502\n",
|
||||
"\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n",
|
||||
" \u2502 HTTP 402 \u2192 pay \u2192 retry\n",
|
||||
"\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u25bc\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n",
|
||||
"\u2502 \u2601\ufe0f AgentCore payments \u2502\u2500\u2500\u25b6\u2502 \ud83c\udfe6 Wallet Provider\u2502\n",
|
||||
"\u2502 Payment Manager \u2502 \u2502 Coinbase CDP \u2502\n",
|
||||
"\u2502 Session ($1.00 budget) \u2502 \u2502 \u2014 or \u2014 \u2502\n",
|
||||
"\u2502 Instrument (embedded wallet) \u2502 \u2502 Stripe Privy \u2502\n",
|
||||
"\u2502 ProcessPayment (sign + proof) \u2502 \u2502 (routed by \u2502\n",
|
||||
"\u2502 \u2502 \u2502 PaymentConnector)\u2502\n",
|
||||
"\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n",
|
||||
"┌─────────────────────────────────┐\n",
|
||||
"│ 🧑💻 Developer Code │\n",
|
||||
"│ │\n",
|
||||
"│ Strands Agent │\n",
|
||||
"│ + AgentCorePaymentsPlugin │\n",
|
||||
"│ + MCPClient (streamable HTTP) │\n",
|
||||
"└──────────┬──────────────────────┘\n",
|
||||
" │ MCP protocol\n",
|
||||
"┌──────────▼──────────────────────┐\n",
|
||||
"│ 🔀 AgentCore Gateway │\n",
|
||||
"│ Target: Coinbase x402 Bazaar │\n",
|
||||
"│ (No outbound auth) │\n",
|
||||
"└──────────┬──────────────────────┘\n",
|
||||
" │\n",
|
||||
"┌──────────▼──────────────────────┐\n",
|
||||
"│ 🌐 Coinbase x402 Bazaar │\n",
|
||||
"│ search_resources → discover │\n",
|
||||
"│ proxy_tool_call → call + pay │\n",
|
||||
"└──────────┬──────────────────────┘\n",
|
||||
" │ HTTP 402 → pay → retry\n",
|
||||
"┌──────────▼──────────────────────┐ ┌──────────────────┐\n",
|
||||
"│ ☁️ AgentCore payments │──▶│ 🏦 Wallet Provider│\n",
|
||||
"│ Payment Manager │ │ Coinbase CDP │\n",
|
||||
"│ Session ($1.00 budget) │ │ — or — │\n",
|
||||
"│ Instrument (embedded wallet) │ │ Stripe Privy │\n",
|
||||
"│ ProcessPayment (sign + proof) │ │ (routed by │\n",
|
||||
"│ │ │ PaymentConnector)│\n",
|
||||
"└─────────────────────────────────┘ └──────────────────┘\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"The key difference from Tutorial 01: the agent doesn't know which URLs to call. It discovers tools at runtime via `search_resources`, then calls them via `proxy_tool_call`. The payment infrastructure is the same.\n",
|
||||
"\n",
|
||||
"### Wallet-agnostic by design\n",
|
||||
"\n",
|
||||
"The agent code in this notebook is identical whether you configured Coinbase CDP or Stripe (Privy) in Tutorial 00. The `AgentCorePaymentsPlugin` receives a `payment_instrument_id` \u2014 AgentCore payments knows which wallet provider backs that instrument based on the PaymentConnector. The same code, same Gateway, same Bazaar tools \u2014 only the `.env` values differ. This is a core design principle of AgentCore payments: developers write payment logic once, and the service handles provider routing.\n",
|
||||
"The agent code in this notebook is the same whether you configured Coinbase CDP or Stripe (Privy) in Tutorial 00. The `AgentCorePaymentsPlugin` receives a `payment_instrument_id` — AgentCore payments knows which wallet provider backs that instrument based on the PaymentConnector. The same code, same Gateway, same Bazaar tools — only the `.env` values differ. This is a core design principle of AgentCore payments: developers write payment logic once, and the service handles provider routing.\n",
|
||||
"\n",
|
||||
"> **Testnet only.** This tutorial uses Base Sepolia (Ethereum) with free USDC from [faucet.circle.com](https://faucet.circle.com/). Testnet USDC has no real-world value.\n"
|
||||
]
|
||||
@@ -72,12 +72,12 @@
|
||||
"source": [
|
||||
"## Prerequisites\n",
|
||||
"\n",
|
||||
"* [Tutorial 00 \u2014 Setup AgentCore payments](../00-setup-agentcore-payments/) completed (`.env` exists with payment manager, instrument, session)\n",
|
||||
"* Wallet funded with testnet USDC \u2014 see the [Circle USDC Faucet guide](https://faucet.circle.com/) (select Base Sepolia, paste your wallet address from Tutorial 00)\n",
|
||||
"* [Tutorial 00 — Setup AgentCore payments](../00-setup-agentcore-payments/) completed (`.env` exists with payment manager, instrument, session)\n",
|
||||
"* Wallet funded with testnet USDC — see the [Circle USDC Faucet guide](https://faucet.circle.com/) (select Base Sepolia, paste your wallet address from Tutorial 00)\n",
|
||||
"* AgentCore CLI: `npm install -g @aws/agentcore`\n",
|
||||
"* `pip install -r requirements.txt`\n",
|
||||
"\n",
|
||||
"This tutorial works with any wallet provider you configured in Tutorial 00 - Coinbase CDP or Stripe (Privy). The agent code is identical regardless of your choice.\n",
|
||||
"This tutorial works with either wallet provider you configured in Tutorial 00 - Coinbase CDP or Stripe (Privy). The agent code is the same regardless of your choice.\n",
|
||||
"\n",
|
||||
"Your AWS credentials need the IAM permissions created by Tutorial 00 (`setup_payment_roles()`). If you can run Tutorial 00 successfully, you have the required permissions."
|
||||
]
|
||||
@@ -89,7 +89,7 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"!pip install -r requirements.txt --quiet"
|
||||
"%pip install -r requirements.txt --quiet"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -115,7 +115,7 @@
|
||||
"id": "4fc1f0a9",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Step 1 \u2014 Create the Gateway with Bazaar Target\n",
|
||||
"## Step 1 — Create the Gateway with Bazaar Target\n",
|
||||
"\n",
|
||||
"> **Cost notice:** AgentCore Gateway deployments incur AWS charges. Run cleanup when finished to avoid ongoing costs.\n",
|
||||
"\n",
|
||||
@@ -124,14 +124,14 @@
|
||||
"### Option A: AgentCore Console (recommended)\n",
|
||||
"\n",
|
||||
"1. Open the [Amazon Bedrock AgentCore console](https://console.aws.amazon.com/bedrock-agentcore/)\n",
|
||||
"2. Navigate to Gateway \u2192 Create Gateway \u2192 Add Target\n",
|
||||
"2. Navigate to Gateway → Create Gateway → Add Target\n",
|
||||
"3. Target type: **Integrations**\n",
|
||||
"4. Select **Coinbase x402 Bazaar**\n",
|
||||
"5. No outbound auth needed (No Authorization is the default)\n",
|
||||
"\n",
|
||||
"### Option B: AgentCore CLI\n",
|
||||
"\n",
|
||||
"> **Note:** The AgentCore CLI does not support the **Integrations** target type (which auto-configures Coinbase x402 Bazaar). With the CLI, you add the Bazaar as a standard `mcp-server` target using its endpoint URL directly. The result is the same \u2014 the Bazaar MCP server is exposed through your Gateway.\n",
|
||||
"> **Note:** The AgentCore CLI does not support the **Integrations** target type (which auto-configures Coinbase x402 Bazaar). With the CLI, you add the Bazaar as a standard `mcp-server` target using its endpoint URL directly. The result is the same — the Bazaar MCP server is exposed through your Gateway.\n",
|
||||
"\n",
|
||||
"```bash\n",
|
||||
"# 1. Create an AgentCore project (skip if you already have one from Tutorial 02)\n",
|
||||
@@ -166,7 +166,7 @@
|
||||
"TOKEN_URL=https://<domain>.auth.<region>.amazoncognito.com/oauth2/token\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"The `agentcore fetch access` output tells you the URL and which auth your Gateway requires. If you used `agentcore add gateway` with no `--authorizer-type` flag, it defaults to NONE auth \u2014 you only need `GATEWAY_URL`.\n",
|
||||
"The `agentcore fetch access` output tells you the URL and which auth your Gateway requires. If you used `agentcore add gateway` with no `--authorizer-type` flag, it defaults to NONE auth — you only need `GATEWAY_URL`.\n",
|
||||
"\n",
|
||||
"Once you have the Gateway URL, paste it in the cell below to save it to `.env`:"
|
||||
]
|
||||
@@ -199,11 +199,11 @@
|
||||
"id": "53080222",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Step 2 \u2014 Load Payment Config\n",
|
||||
"## Step 2 — Load Payment Config\n",
|
||||
"\n",
|
||||
"This step loads the payment resources created in [Tutorial 00](../00-setup-agentcore-payments/) from `.env`. The same config loading pattern is used in every tutorial (01\u201306). No new resources are created here.\n",
|
||||
"This step loads the payment resources created in [Tutorial 00](../00-setup-agentcore-payments/) from `.env`. The same config loading pattern is used in every tutorial (01–06). No new resources are created here.\n",
|
||||
"\n",
|
||||
"### Step 2a \u2014 Payment Config (same as all tutorials)"
|
||||
"### Step 2a — Payment Config (same as all tutorials)"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -243,7 +243,7 @@
|
||||
"manager = PaymentManager(payment_manager_arn=PAYMENT_MANAGER_ARN, region_name=REGION)\n",
|
||||
"instr = manager.get_payment_instrument(user_id=USER_ID, payment_instrument_id=INSTRUMENT_ID)\n",
|
||||
"instr_status = instr.get('status', 'UNKNOWN')\n",
|
||||
"assert instr_status == 'ACTIVE', f'Instrument is {instr_status} \u2014 fund and delegate in Tutorial 00/03 first'\n",
|
||||
"assert instr_status == 'ACTIVE', f'Instrument is {instr_status} — fund and delegate in Tutorial 00/03 first'\n",
|
||||
"\n",
|
||||
"print_summary('Payment Config',\n",
|
||||
" manager_arn=PAYMENT_MANAGER_ARN,\n",
|
||||
@@ -260,7 +260,7 @@
|
||||
"id": "gateway_config_section",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Step 2b \u2014 Gateway Config"
|
||||
"### Step 2b — Gateway Config"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -272,7 +272,7 @@
|
||||
"source": [
|
||||
"import os\n",
|
||||
"\n",
|
||||
"# Gateway URL \u2014 set this after creating the gateway in Step 1\n",
|
||||
"# Gateway URL — set this after creating the gateway in Step 1\n",
|
||||
"GATEWAY_URL = os.environ.get('GATEWAY_URL', '')\n",
|
||||
"if not GATEWAY_URL:\n",
|
||||
" raise ValueError(\n",
|
||||
@@ -289,9 +289,9 @@
|
||||
"id": "c1144bd7",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Step 3 \u2014 Create Payment Session\n",
|
||||
"## Step 3 — Create Payment Session\n",
|
||||
"\n",
|
||||
"A payment session defines the budget and expiry for this interaction. The Payment Manager and Instrument from Tutorial 00 are long-lived resources \u2014 sessions are created as needed."
|
||||
"A payment session defines the budget and expiry for this interaction. The Payment Manager and Instrument from Tutorial 00 are long-lived resources — sessions are created as needed."
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -308,7 +308,7 @@
|
||||
" expiry_time_in_minutes=60,\n",
|
||||
")\n",
|
||||
"SESSION_ID = sess_resp['paymentSessionId']\n",
|
||||
"print(f'\u2705 Session: {SESSION_ID} (budget: $1.00)')"
|
||||
"print(f'✅ Session: {SESSION_ID} (budget: $1.00)')"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -316,7 +316,7 @@
|
||||
"id": "abda0100",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Step 4 \u2014 Connect to Gateway and Create Agent\n",
|
||||
"## Step 4 — Connect to Gateway and Create Agent\n",
|
||||
"\n",
|
||||
"Connect to the Gateway MCP endpoint using the Strands MCP client. The Gateway routes to the Bazaar, which exposes `search_resources` and `proxy_tool_call` as MCP tools.\n",
|
||||
"\n",
|
||||
@@ -350,7 +350,7 @@
|
||||
" AgentCorePaymentsPluginConfig,\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"# For Gateway auth \u2014 auto-detect from .env\n",
|
||||
"# For Gateway auth — auto-detect from .env\n",
|
||||
"# If your Gateway uses CUSTOM_JWT, set CLIENT_ID, CLIENT_SECRET, TOKEN_URL in .env.\n",
|
||||
"# If NONE auth (the default), leave them unset.\n",
|
||||
"# Run `agentcore fetch access` to see which auth your Gateway requires.\n",
|
||||
@@ -374,8 +374,8 @@
|
||||
" timeout=timedelta(seconds=120),\n",
|
||||
"))\n",
|
||||
"\n",
|
||||
"# Payment plugin \u2014 uses the Payment Manager, Instrument, and Session.\n",
|
||||
"# The plugin handles x402 402 responses automatically: intercept \u2192 sign \u2192 retry.\n",
|
||||
"# Payment plugin — uses the Payment Manager, Instrument, and Session.\n",
|
||||
"# The plugin handles x402 402 responses automatically: intercept → sign → retry.\n",
|
||||
"# No manual payment code needed.\n",
|
||||
"payment_plugin = AgentCorePaymentsPlugin(\n",
|
||||
" config=AgentCorePaymentsPluginConfig(\n",
|
||||
@@ -388,11 +388,11 @@
|
||||
" )\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"SYSTEM_PROMPT = \"\"\"You are a research agent with access to the Coinbase x402 Bazaar \u2014 a marketplace of paid tools.\n",
|
||||
"SYSTEM_PROMPT = \"\"\"You are a research agent with access to the Coinbase x402 Bazaar — a marketplace of paid tools.\n",
|
||||
"\n",
|
||||
"You can:\n",
|
||||
"1. Use search_resources to discover available paid tools (filter by network, query, etc.)\n",
|
||||
"2. Use proxy_tool_call to call a discovered tool \u2014 payment is handled automatically\n",
|
||||
"2. Use proxy_tool_call to call a discovered tool — payment is handled automatically\n",
|
||||
"\n",
|
||||
"When asked to find information:\n",
|
||||
"- First search for relevant tools on the Bazaar\n",
|
||||
@@ -410,7 +410,7 @@
|
||||
" plugins=[payment_plugin],\n",
|
||||
" system_prompt=SYSTEM_PROMPT,\n",
|
||||
")\n",
|
||||
"print(f'\u2705 Agent created with {len(mcp_client.list_tools_sync())} Bazaar tools + payment plugin')"
|
||||
"print(f'✅ Agent created with {len(mcp_client.list_tools_sync())} Bazaar tools + payment plugin')\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -418,13 +418,13 @@
|
||||
"id": "179825a3",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Step 5 \u2014 Discover and Call Paid Tools\n",
|
||||
"## Step 5 — Discover and Call Paid Tools\n",
|
||||
"\n",
|
||||
"This is the key difference from [Tutorial 01](../01-agents-payments-and-limits/). In Tutorial 01, you told the agent which URL to call. Here, the agent discovers what to call on its own using `search_resources`, then pays and calls it using `proxy_tool_call`. The developer doesn't pre-configure which tools exist \u2014 the agent finds them at runtime.\n",
|
||||
"This is the key difference from [Tutorial 01](../01-agents-payments-and-limits/). In Tutorial 01, you told the agent which URL to call. Here, the agent discovers what to call on its own using `search_resources`, then pays and calls it using `proxy_tool_call`. The developer doesn't pre-configure which tools exist — the agent finds them at runtime.\n",
|
||||
"\n",
|
||||
"The use cases from the docs: research agents accessing paid data sources, financial analysis agents accessing market data, and agents browsing paid content \u2014 all start with discovery.\n",
|
||||
"The use cases from the docs: research agents accessing paid data sources, financial analysis agents accessing market data, and agents browsing paid content — all start with discovery.\n",
|
||||
"\n",
|
||||
"### Step 5a \u2014 Search and Call a Paid Tool"
|
||||
"### Step 5a — Search and Call a Paid Tool"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -439,7 +439,7 @@
|
||||
" 'Tell me what tools are available, their prices, and what data they provide. '\n",
|
||||
" 'Then pick the most relevant one, call it, and summarize the results with the cost.'\n",
|
||||
")\n",
|
||||
"print(result.message)"
|
||||
"print(result.message)\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -447,9 +447,9 @@
|
||||
"id": "f8ec4b10",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Step 5b \u2014 Multi-Tool Discovery: Compare Prices Across Categories\n",
|
||||
"### Step 5b — Multi-Tool Discovery: Compare Prices Across Categories\n",
|
||||
"\n",
|
||||
"The agent searches across different categories and compares prices \u2014 showing that it can evaluate multiple paid services before deciding which to call. This maps to the endpoint discoverability feature: 10,000+ pay-per-use x402 endpoints, and the agent shops for the best option within its budget."
|
||||
"The agent searches across different categories and compares prices — showing that it can evaluate multiple paid services before deciding which to call. This maps to the endpoint discoverability feature: 10,000+ pay-per-use x402 endpoints, and the agent shops for the best option within its budget."
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -465,7 +465,7 @@
|
||||
" 'For each category, list the available tools with their prices. '\n",
|
||||
" 'Then tell me which tool in each category is the cheapest.'\n",
|
||||
")\n",
|
||||
"print(result.message)"
|
||||
"print(result.message)\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -473,9 +473,9 @@
|
||||
"id": "3367af7e",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Step 5c \u2014 Budget-Aware Tool Selection\n",
|
||||
"### Step 5c — Budget-Aware Tool Selection\n",
|
||||
"\n",
|
||||
"The agent checks its remaining budget before calling an expensive tool. If the budget is low, it picks a cheaper alternative. This shows how payment limits and tool discovery work together \u2014 the agent makes cost-aware decisions at runtime."
|
||||
"The agent checks its remaining budget before calling an expensive tool. If the budget is low, it picks a cheaper alternative. This shows how payment limits and tool discovery work together — the agent makes cost-aware decisions at runtime."
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -499,7 +499,7 @@
|
||||
" 'Pick the cheapest one and call it. '\n",
|
||||
" 'If nothing is under $0.10, tell me what the cheapest option costs.'\n",
|
||||
")\n",
|
||||
"print(result.message)"
|
||||
"print(result.message)\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -507,9 +507,9 @@
|
||||
"id": "2f59a82b",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Step 5d \u2014 Multiple Bazaar Calls in One Session\n",
|
||||
"### Step 5d — Multiple Bazaar Calls in One Session\n",
|
||||
"\n",
|
||||
"The agent calls multiple paid tools in sequence within a single session. The session budget tracks cumulative spend across all calls \u2014 showing that one payment stack handles multiple merchants without per-provider setup."
|
||||
"The agent calls multiple paid tools in sequence within a single session. The session budget tracks cumulative spend across all calls — showing that one payment stack handles multiple merchants without per-provider setup."
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -535,7 +535,7 @@
|
||||
"id": "88d5ac6c",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Step 6 \u2014 Check Session Spend"
|
||||
"## Step 6 — Check Session Spend"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -569,7 +569,7 @@
|
||||
"source": [
|
||||
"## View Payment Traces\n",
|
||||
"\n",
|
||||
"Every Bazaar tool call that triggered a payment produced a trace. View them on the Amazon CloudWatch GenAI Observability Dashboard."
|
||||
"Every Bazaar tool call that triggered a payment produced a trace. View them on the CloudWatch GenAI Observability Dashboard.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -579,8 +579,8 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"print(f'\ud83d\udd0d View your agent traces: Amazon CloudWatch \u2192 GenAI Observability Dashboard')\n",
|
||||
"print(f' https://{REGION}.console.aws.amazon.com/cloudwatch/home?region={REGION}#gen-ai-observability/agent-core')"
|
||||
"print(f'🔍 View your agent traces: CloudWatch → GenAI Observability Dashboard')\n",
|
||||
"print(f' https://{REGION}.console.aws.amazon.com/cloudwatch/home?region={REGION}#gen-ai-observability/agent-core')\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -595,19 +595,19 @@
|
||||
"| AgentCore payments feature | What this tutorial demonstrated |\n",
|
||||
"|---------------------------|-------------------------------|\n",
|
||||
"| Endpoint discoverability | Agent connected to one Gateway URL and discovered tools across market news, weather data, and crypto news categories at runtime |\n",
|
||||
"| Payment processing | `AgentCorePaymentsPlugin` handled 402 \u2192 sign \u2192 retry for every Bazaar tool call with no developer payment code |\n",
|
||||
"| Payment processing | `AgentCorePaymentsPlugin` handled 402 → sign → retry for every Bazaar tool call with no developer payment code |\n",
|
||||
"| Payment limits | Session budget tracked cumulative spend across multiple paid tool calls from different merchants |\n",
|
||||
"| Wallet integration | Same notebook, same agent code, same Gateway \u2014 works with Coinbase CDP or Stripe (Privy). Only the `.env` values from Tutorial 00 differ. |\n",
|
||||
"| Wallet integration | Same notebook, same agent code, same Gateway — works with Coinbase CDP or Stripe (Privy). Only the `.env` values from Tutorial 00 differ. |\n",
|
||||
"\n",
|
||||
"The contrast with Tutorial 01: there, you told the agent which URL to hit. Here, the agent decided what to call based on the task \u2014 the Research and Financial analysis use cases from the docs.\n",
|
||||
"The contrast with Tutorial 01: there, you told the agent which URL to hit. Here, the agent decided what to call based on the task — the Research and Financial analysis use cases from the docs.\n",
|
||||
"\n",
|
||||
"### Wallet-agnostic by design\n",
|
||||
"\n",
|
||||
"This is a core design principle of AgentCore payments. The agent code never references Coinbase or Privy. It receives a `payment_instrument_id` in the plugin config \u2014 AgentCore payments knows which wallet provider backs that instrument based on the PaymentConnector configured in Tutorial 00. The same deployed agent, the same Gateway, the same Bazaar tools serve both wallet providers without code changes. A developer who switches from Coinbase to Privy (or adds both) only changes the `.env` \u2014 zero code changes in the notebook or agent.\n",
|
||||
"This is a core design principle of AgentCore payments. The agent code never references Coinbase or Privy. It receives a `payment_instrument_id` in the plugin config — AgentCore payments knows which wallet provider backs that instrument based on the PaymentConnector configured in Tutorial 00. The same deployed agent, the same Gateway, the same Bazaar tools serve both wallet providers without code changes. A developer who switches from Coinbase to Privy (or adds both) only changes the `.env` — zero code changes in the notebook or agent.\n",
|
||||
"\n",
|
||||
"### Role separation for deployed agents\n",
|
||||
"\n",
|
||||
"This notebook runs locally under your AWS credentials. When deployed, the runtime process runs under ProcessPaymentRole \u2014 the plugin calls `ProcessPayment` on behalf of the agent within the budget set by the app backend. The runtime cannot create sessions, modify limits, or provision wallets. The agent (LLM) never calls `ProcessPayment` directly. See Tutorial 02 for the full role separation implementation.\n",
|
||||
"This notebook runs locally under your AWS credentials. When deployed, the runtime process runs under ProcessPaymentRole — the plugin calls `ProcessPayment` on behalf of the agent within the budget set by the app backend. The runtime cannot create sessions, modify limits, or provision wallets. The agent (LLM) never calls `ProcessPayment` directly. See Tutorial 02 for the full role separation implementation.\n",
|
||||
"\n",
|
||||
"To test role separation locally, pass an assumed-role session to the SDK client:\n",
|
||||
"\n",
|
||||
@@ -619,12 +619,12 @@
|
||||
"manager = PaymentManager(payment_manager_arn=ARN, region_name=REGION)\n",
|
||||
"session = manager.create_payment_session(user_id=USER_ID, ...)\n",
|
||||
"\n",
|
||||
"# Agent runs under ProcessPaymentRole \u2014 can only ProcessPayment\n",
|
||||
"# Agent runs under ProcessPaymentRole — can only ProcessPayment\n",
|
||||
"agent_session = assume_role(boto3.Session(), PROCESS_PAYMENT_ROLE_ARN, 'agent')\n",
|
||||
"agent_manager = PaymentManager(\n",
|
||||
" payment_manager_arn=ARN, boto3_session=agent_session\n",
|
||||
")\n",
|
||||
"# Pass agent_manager to the plugin \u2014 it cannot create sessions or modify budgets\n",
|
||||
"# Pass agent_manager to the plugin — it cannot create sessions or modify budgets\n",
|
||||
"```"
|
||||
]
|
||||
},
|
||||
@@ -652,7 +652,7 @@
|
||||
"\n",
|
||||
"Sessions expire automatically after their `expiryTimeInMinutes`.\n",
|
||||
"\n",
|
||||
"**If you plan to continue with Tutorials 05\u201306, do NOT clean up.** The Gateway and payment resources are reused across tutorials.\n",
|
||||
"**If you plan to continue with Tutorials 05–06, do NOT clean up.** The Gateway and payment resources are reused across tutorials.\n",
|
||||
"\n",
|
||||
"Only run cleanup when you are done with all tutorials:\n",
|
||||
"\n",
|
||||
@@ -680,9 +680,9 @@
|
||||
"\n",
|
||||
"### Next steps\n",
|
||||
"\n",
|
||||
"- **Custom Lambda interceptors** \u2014 Add Lambda-based interceptors to your AgentCore Gateway to transform, filter, or enrich requests before they reach Coinbase Bazaar\n",
|
||||
"- **Deploying to AgentCore Runtime** \u2014 Follow the Tutorial 02 pattern to deploy this agent with ProcessPaymentRole enforcement\n",
|
||||
"- **Multi-agent with Gateway** \u2014 See Tutorial 06 for running multiple agents with independent budgets against the same Gateway target"
|
||||
"- **Custom Lambda interceptors** — Add Lambda-based interceptors to your AgentCore Gateway to transform, filter, or enrich requests before they reach Coinbase Bazaar\n",
|
||||
"- **Deploying to AgentCore Runtime** — Follow the Tutorial 02 pattern to deploy this agent with ProcessPaymentRole enforcement\n",
|
||||
"- **Multi-agent with Gateway** — See Tutorial 06 for running multiple agents with independent budgets against the same Gateway target"
|
||||
]
|
||||
}
|
||||
],
|
||||
@@ -707,4 +707,4 @@
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
}
|
||||
|
||||
+5
-3
@@ -1,4 +1,4 @@
|
||||
# Agent with Browser Tool — Pay for Paywalled Content
|
||||
# Agent with Browser Tool — Pay for Gated Content
|
||||
|
||||
> **Pattern reference.** This notebook demonstrates the browser + payment architecture. To run it end-to-end, you need an x402-enabled content endpoint.
|
||||
|
||||
@@ -69,13 +69,15 @@ Use the plugin pattern for API calls. Use the browser pattern when you need to m
|
||||
* `python -m playwright install chromium`
|
||||
* An x402-enabled endpoint to browse
|
||||
|
||||
This tutorial works with either wallet provider you configured in Tutorial 00 (Coinbase CDP or Stripe/Privy). The agent code is identical regardless of your choice.
|
||||
This tutorial works with either wallet provider you configured in Tutorial 00 (Coinbase CDP or Stripe/Privy). The agent code is the same regardless of your choice.
|
||||
|
||||
> **Testnet only.** All code uses Base Sepolia (Ethereum) with free USDC from [faucet.circle.com](https://faucet.circle.com/). Testnet USDC has no real-world value.
|
||||
|
||||
## Cleanup
|
||||
|
||||
Browser sessions expire automatically after the configured timeout. Payment sessions expire after `expiryTimeInMinutes`. No manual cleanup is needed for this tutorial.
|
||||
> **Cost notice:** AgentCore Browser sessions incur charges per minute of browser runtime. Payment sessions are free but the underlying Payment Manager and Instruments incur standard AWS charges until deleted via Tutorial 00.
|
||||
|
||||
AgentCore Browser sessions (BrowserClient) expire automatically after the configured timeout. Payment sessions expire after their configured `expiryTimeInMinutes`. No manual cleanup is needed for sessions created in this tutorial.
|
||||
|
||||
## Conclusion
|
||||
|
||||
|
||||
+7
-7
@@ -83,7 +83,7 @@
|
||||
"* `pip install -r requirements.txt`\n",
|
||||
"* `python -m playwright install chromium`\n",
|
||||
"\n",
|
||||
"This tutorial works with any wallet provider you configured in Tutorial 00 - Coinbase CDP or Stripe (Privy). Your AWS credentials need the IAM permissions created by Tutorial 00 (`setup_payment_roles()`)."
|
||||
"This tutorial works with either wallet provider you configured in Tutorial 00 - Coinbase CDP or Stripe (Privy). Your AWS credentials need the IAM permissions created by Tutorial 00 (`setup_payment_roles()`)."
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -93,7 +93,7 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"!pip install -r requirements.txt --quiet\n",
|
||||
"%pip install -r requirements.txt --quiet\n",
|
||||
"!python -m playwright install chromium"
|
||||
]
|
||||
},
|
||||
@@ -188,7 +188,7 @@
|
||||
"source": [
|
||||
"## Step 3 — Build the `browse_with_payment` Tool\n",
|
||||
"\n",
|
||||
"This is the core of the tutorial. We build a custom `@tool` because the payment flow must happen inside the browser session (the plugin cannot maintain browser state across retries). The tool:\n",
|
||||
"This is the core of the tutorial. The `@tool` below is a custom tool because the payment flow must happen inside the browser session (the plugin cannot maintain browser state across retries). The tool:\n",
|
||||
"1. Starts a managed browser session via AgentCore Browser (`BrowserClient`)\n",
|
||||
"2. Connects Playwright to the managed browser via WebSocket\n",
|
||||
"3. Navigates to the URL\n",
|
||||
@@ -216,7 +216,7 @@
|
||||
"source": [
|
||||
"## Step 4 — Build the `browse_with_payment` Tool\n",
|
||||
"\n",
|
||||
"This is the core of the tutorial. We build a custom `@tool` because the payment flow must happen inside the browser session (the plugin cannot maintain browser state across retries). The tool:\n",
|
||||
"This is the core of the tutorial. The `@tool` below is a custom tool because the payment flow must happen inside the browser session (the plugin cannot maintain browser state across retries). The tool:\n",
|
||||
"1. Starts a managed browser session via AgentCore Browser (`BrowserClient`)\n",
|
||||
"2. Connects Playwright to the managed browser via WebSocket\n",
|
||||
"3. Navigates to the URL\n",
|
||||
@@ -470,7 +470,7 @@
|
||||
"source": [
|
||||
"## View Payment Traces\n",
|
||||
"\n",
|
||||
"Every payment produces a trace. View them on the Amazon CloudWatch GenAI Observability Dashboard."
|
||||
"Every payment produces a trace. View them on the CloudWatch GenAI Observability Dashboard.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -480,8 +480,8 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"print(f'🔍 View your agent traces: Amazon CloudWatch → GenAI Observability Dashboard')\n",
|
||||
"print(f' https://{REGION}.console.aws.amazon.com/cloudwatch/home?region={REGION}#gen-ai-observability/agent-core')"
|
||||
"print(f'🔍 View your agent traces: CloudWatch → GenAI Observability Dashboard')\n",
|
||||
"print(f' https://{REGION}.console.aws.amazon.com/cloudwatch/home?region={REGION}#gen-ai-observability/agent-core')\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
+5
-1
@@ -85,13 +85,17 @@ Your AWS credentials need the IAM permissions created by Tutorial 00 (`setup_pay
|
||||
|
||||
## Cleanup
|
||||
|
||||
> **Cost notice:** AgentCore Runtime deployments, online evaluations, and CloudWatch observability incur AWS charges. Run cleanup when finished to avoid ongoing costs.
|
||||
|
||||
AgentCore Runtime and online evaluations incur charges. Remove when done:
|
||||
|
||||
```bash
|
||||
cd PaymentAgent && agentcore remove all -y
|
||||
```
|
||||
|
||||
This removes the Runtime deployment, evaluation configuration, CloudWatch log groups, and associated resources. Payment sessions expire automatically.
|
||||
This removes the Runtime deployment, evaluation configuration, CloudWatch log groups, and associated resources.
|
||||
|
||||
**Payment sessions** — Expire automatically after their configured `expiryTimeInMinutes` (60 minutes in this tutorial). No manual deletion needed.
|
||||
|
||||
## Conclusion
|
||||
|
||||
|
||||
+14
-10
@@ -12,7 +12,7 @@
|
||||
"\n",
|
||||
"### What this demonstrates\n",
|
||||
"\n",
|
||||
"Three patterns that require orchestration — not just parallel execution:\n",
|
||||
"Three patterns that require orchestration — beyond parallel execution:\n",
|
||||
"\n",
|
||||
"| Demo | Pattern | What it proves |\n",
|
||||
"|------|---------|---------------|\n",
|
||||
@@ -362,7 +362,7 @@
|
||||
"\n",
|
||||
"## Step 5 — Run Three Multi-Agent Demos\n",
|
||||
"\n",
|
||||
"Each demo shows a distinct capability that requires orchestration — not just parallel execution. A spend report follows each execution to prove exactly what happened.\n",
|
||||
"Each demo shows a distinct capability that requires orchestration — beyond parallel execution. A spend report follows each execution to prove exactly what happened.\n",
|
||||
"\n",
|
||||
"| Demo | Pattern | What to watch for |\n",
|
||||
"|------|---------|-------------------|\n",
|
||||
@@ -597,13 +597,7 @@
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Demo 3 — Structural Safety (Orchestrator Cannot Spend)\n",
|
||||
"\n",
|
||||
"The orchestrator has **no payment plugin**. Even if the LLM decides to call a paid endpoint directly, the x402 payment flow cannot execute — there is no plugin to intercept the 402 and sign a transaction.\n",
|
||||
"\n",
|
||||
"This is structural enforcement, not prompt-level. The orchestrator's role is to **route**, not to **pay**."
|
||||
]
|
||||
"source": "## Demo 3 — Structural Safety (Orchestrator Cannot Spend)\n\nThe orchestrator has **no payment plugin**. Even if the LLM decides to call a paid endpoint directly, the x402 payment flow cannot run — there is no plugin to intercept the 402 and sign a transaction.\n\nThis is structural enforcement, not prompt-level. The orchestrator's role is to **route**, not to **pay**."
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
@@ -905,6 +899,16 @@
|
||||
"Same manager. Different connectors. Different wallets. Independent budgets. Full attribution in CloudWatch."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "verification-multi-agent",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Verification\n",
|
||||
"\n",
|
||||
"If the cells above ran without errors, the multi-agent payment orchestrator is deployed. You should see spend reports printed for all three demos above, with each agent's session showing a reduced `availableLimit` — confirming per-agent budget enforcement is working correctly."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
@@ -954,7 +958,7 @@
|
||||
"\n",
|
||||
"If you completed Tutorial 04 and have a Gateway with the Coinbase Bazaar target, you can swap `http_request` for MCP tools. The agents get `search_resources` and `proxy_tool_call` instead of raw HTTP URLs — closer to how you'd build this at scale.\n",
|
||||
"\n",
|
||||
"The payment infrastructure stays identical. Only the tool layer changes.\n",
|
||||
"The payment infrastructure stays the same. Only the tool layer changes.\n",
|
||||
"\n",
|
||||
"```python\n",
|
||||
"from datetime import timedelta\n",
|
||||
|
||||
@@ -117,6 +117,10 @@ Path B (multi-provider):
|
||||
└──► T01–T06 also work
|
||||
```
|
||||
|
||||
## Security Notice
|
||||
|
||||
These tutorials use `.env` files for credential storage for simplicity. For deployed workloads, store all credentials in [AWS Secrets Manager](https://docs.aws.amazon.com/secretsmanager/latest/userguide/intro.html) or Systems Manager Parameter Store. Never commit `.env` files to version control. See the [Security](#security) section for additional guidance.
|
||||
|
||||
## Tutorials
|
||||
|
||||
Each tutorial maps to one or more AgentCore payments features. Start with Tutorial 00, then pick any path.
|
||||
@@ -178,10 +182,14 @@ The Bazaar exposes three interfaces:
|
||||
|
||||
## Wallet-Agnostic Design
|
||||
|
||||
All tutorials work with any wallet provider you configured in Tutorial 00 - Coinbase CDP or Stripe (Privy). The agent code is identical regardless of your choice — only the `.env` values differ.
|
||||
The tutorials are designed to work with either supported wallet provider you configured in Tutorial 00 - Coinbase CDP or Stripe (Privy). The agent code is the same regardless of your choice — only the `.env` values differ.
|
||||
|
||||
## Cleanup
|
||||
|
||||
> **Cost notice:** AgentCore Runtime deployments, Gateway, payment sessions, and CloudWatch observability incur AWS charges. Run cleanup after completing experimentation to avoid ongoing costs.
|
||||
|
||||
> **Warning:** Cleanup is irreversible and permanently deletes all payment resources, transaction history, and audit logs. Verify you have exported any data you need before proceeding.
|
||||
|
||||
When you are done with the tutorials, clean up resources to avoid unnecessary charges:
|
||||
|
||||
1. **Runtime deployments** — Remove deployed agents and gateways:
|
||||
@@ -205,3 +213,7 @@ These tutorials use testnet resources with no real-world value. When building fo
|
||||
- **Monitoring** — Enable CloudWatch Logs for payment traces. Set up alarms for unusual spending patterns or failed payment attempts.
|
||||
|
||||
Follow the [AWS Shared Responsibility Model](https://aws.amazon.com/compliance/shared-responsibility-model/) — you are responsible for securing your credentials, IAM policies, wallet access, and session budgets.
|
||||
|
||||
## Conclusion
|
||||
|
||||
These tutorials cover the full lifecycle of payment-enabled AI agents with Amazon Bedrock AgentCore payments: wallet setup, local agent development, Runtime deployment, wallet operations, Gateway integration, browser-based payments, and multi-agent orchestration. Start with Tutorial 00 and the provider setup guide for your chosen wallet, then follow whichever path fits your use case. For production guidance, see the [AgentCore payments documentation](https://docs.aws.amazon.com/bedrock-agentcore/) and review the Security section above.
|
||||
|
||||
@@ -132,9 +132,11 @@ PAYMENT_ROLE_DEFINITIONS = {
|
||||
"bedrock-agentcore:ListPaymentCredentialProviders",
|
||||
"bedrock-agentcore:DeletePaymentCredentialProvider",
|
||||
"bedrock-agentcore:UpdatePaymentCredentialProvider",
|
||||
"bedrock-agentcore:CreateTokenVault",
|
||||
"bedrock-agentcore:AllowVendedLogDeliveryForResource",
|
||||
],
|
||||
"pass_role": True,
|
||||
"secrets_manager_write": True,
|
||||
},
|
||||
MANAGEMENT_ROLE: {
|
||||
"description": "AgentCore payments: data plane management (instruments, sessions)",
|
||||
@@ -153,7 +155,7 @@ PAYMENT_ROLE_DEFINITIONS = {
|
||||
"deny": ["bedrock-agentcore:ProcessPayment"],
|
||||
},
|
||||
PROCESS_PAYMENT_ROLE: {
|
||||
"description": "AgentCore payments: agent execution (ProcessPayment + read queries)",
|
||||
"description": "AgentCore payments: agent runtime (ProcessPayment + read queries)",
|
||||
"trust": "account",
|
||||
"allow": [
|
||||
"bedrock-agentcore:ProcessPayment",
|
||||
@@ -181,6 +183,9 @@ def setup_payment_roles(region=None):
|
||||
Checks if each role exists first. Creates only what's missing.
|
||||
Idempotent — safe to run multiple times.
|
||||
|
||||
Note: Creates IAM roles that persist until explicitly deleted. Run the
|
||||
cleanup cell in Tutorial 00 to remove them when no longer needed.
|
||||
|
||||
Args:
|
||||
region: AWS region. Defaults to AWS_REGION env var or us-west-2.
|
||||
|
||||
@@ -281,11 +286,29 @@ def setup_payment_roles(region=None):
|
||||
"Sid": "Allow",
|
||||
"Effect": "Allow",
|
||||
"Action": config["allow"],
|
||||
"Resource": "*",
|
||||
"Resource": f"arn:aws:bedrock-agentcore:{region}:{account_id}:*",
|
||||
}
|
||||
],
|
||||
}
|
||||
|
||||
# Add SecretsManager write access for ControlPlaneRole
|
||||
# Resource must be "*" because CreateSecret targets secrets that don't exist yet
|
||||
if config.get("secrets_manager_write"):
|
||||
allow_policy["Statement"].append(
|
||||
{
|
||||
"Sid": "SecretsManagerWrite",
|
||||
"Effect": "Allow",
|
||||
"Action": [
|
||||
"secretsmanager:CreateSecret",
|
||||
"secretsmanager:PutSecretValue",
|
||||
"secretsmanager:UpdateSecret",
|
||||
"secretsmanager:DeleteSecret",
|
||||
"secretsmanager:TagResource",
|
||||
],
|
||||
"Resource": "*",
|
||||
}
|
||||
)
|
||||
|
||||
# Add SecretsManager access for ResourceRetrievalRole
|
||||
if config.get("secrets_manager"):
|
||||
allow_policy["Statement"].append(
|
||||
@@ -320,7 +343,7 @@ def setup_payment_roles(region=None):
|
||||
"Sid": "Deny",
|
||||
"Effect": "Deny",
|
||||
"Action": config["deny"],
|
||||
"Resource": "*",
|
||||
"Resource": f"arn:aws:bedrock-agentcore:{region}:{account_id}:*",
|
||||
}
|
||||
],
|
||||
}
|
||||
@@ -634,6 +657,10 @@ def enable_observability(
|
||||
Creates delivery sources, destinations, and deliveries for both APPLICATION_LOGS
|
||||
and TRACES. Optionally configures X-Ray span delivery to CloudWatch Logs.
|
||||
|
||||
**Cost notice:** This function creates CloudWatch log groups, delivery sources,
|
||||
delivery destinations, and X-Ray resources that may incur AWS charges. Delete
|
||||
the log group ``/aws/vendedlogs/bedrock-agentcore/<manager-id>`` when finished.
|
||||
|
||||
After enabling, any data plane API call (CreateInstrument, ProcessPayment, etc.)
|
||||
produces logs and trace data in the configured CloudWatch Log Group.
|
||||
|
||||
@@ -663,7 +690,7 @@ def enable_observability(
|
||||
- bedrock-agentcore:AllowVendedLogDeliveryForResource
|
||||
"""
|
||||
# Step 1: Allow vended log delivery for the resource
|
||||
# This authorizes the AgentCore service to publish vended logs to your account.
|
||||
# This authorizes the Bedrock AgentCore service to publish vended logs to your account.
|
||||
# Must be called before creating delivery sources/destinations.
|
||||
agentcore_client = boto3.client("bedrock-agentcore-control", region_name=region)
|
||||
try:
|
||||
@@ -755,7 +782,7 @@ def _setup_xray_spans(logs_client, region):
|
||||
"logs:CreateLogGroup",
|
||||
"logs:CreateLogStream",
|
||||
],
|
||||
"Resource": "*",
|
||||
"Resource": "arn:aws:logs:*:*:log-group:/aws/vendedlogs/bedrock-agentcore/*",
|
||||
}
|
||||
],
|
||||
}
|
||||
@@ -898,8 +925,8 @@ def save_privy_authorization_key(env_path, authorization_id, authorization_priva
|
||||
|
||||
Privy's dashboard displays the authorization private key with a ``wallet-auth:``
|
||||
prefix. That prefix is not part of the key itself and must be removed before the
|
||||
key is passed to AgentCore's ``authorizationPrivateKey`` field — AgentCore's
|
||||
validation rejects the prefixed form.
|
||||
key is passed to the Bedrock AgentCore ``authorizationPrivateKey`` field —
|
||||
Bedrock AgentCore validation rejects the prefixed form.
|
||||
|
||||
Args:
|
||||
env_path: Path to the .env file.
|
||||
@@ -947,8 +974,8 @@ def verify_privy_signer_on_wallet(app_id, app_secret, wallet_address_or_id, quor
|
||||
app_id: Privy app ID (``PRIVY_APP_ID``).
|
||||
app_secret: Privy app secret (``PRIVY_APP_SECRET``).
|
||||
wallet_address_or_id: Privy wallet ID or on-chain address.
|
||||
quorum_id: Key quorum ID to look for. AgentCore's
|
||||
``PRIVY_AUTHORIZATION_ID``.
|
||||
quorum_id: Key quorum ID to look for. The Bedrock AgentCore
|
||||
``PRIVY_AUTHORIZATION_ID`` field.
|
||||
|
||||
Returns:
|
||||
True if the quorum is present in ``additional_signers``, else False.
|
||||
|
||||
+1
-1
@@ -139,7 +139,7 @@ OPERATOR CLEANUP (automatic on session expiry)
|
||||
|
||||
> **Note:** This use case provisions an **embedded crypto wallet** via AgentCore.
|
||||
> You do not need a pre-existing Coinbase wallet. The credential provider (CDP API key)
|
||||
> authorises AgentCore to create and manage the wallet on your behalf. After provisioning,
|
||||
> authorizes AgentCore to create and manage the wallet on your behalf. After provisioning,
|
||||
> Step 3 prints a **WalletHub URL** — open it to fund the wallet and grant signing permission.
|
||||
|
||||
> **Important:** `AgentCoreBrowser` is a cloud-managed browser — it cannot reach
|
||||
|
||||
+1
-1
@@ -134,7 +134,7 @@ ${requirementJson}
|
||||
<p>
|
||||
Agentic commerce represents a fundamental shift in how digital transactions occur.
|
||||
Rather than requiring human approval for each micropayment, AI agents can now
|
||||
autonomously negotiate, authorise, and execute payments on behalf of users —
|
||||
autonomously negotiate, authorize, and process payments on behalf of users —
|
||||
within strict, human-defined budget limits.
|
||||
</p>
|
||||
<p>
|
||||
|
||||
+2
-2
@@ -150,7 +150,7 @@ ${requirementJson}
|
||||
<p>
|
||||
Agentic commerce represents a fundamental shift in how digital transactions occur.
|
||||
Rather than requiring human approval for each micropayment, AI agents can now
|
||||
autonomously negotiate, authorise, and execute payments on behalf of users —
|
||||
autonomously negotiate, authorize, and process payments on behalf of users —
|
||||
within strict, human-defined budget limits.
|
||||
</p>
|
||||
<p>
|
||||
@@ -283,7 +283,7 @@ export const handler = async (event: CFEvent): Promise<LambdaResponse | CFReques
|
||||
title: "The Future of Agentic Commerce",
|
||||
content:
|
||||
"Agentic commerce represents a fundamental shift in how digital transactions occur. " +
|
||||
"AI agents can now autonomously negotiate, authorise, and execute payments within strict, " +
|
||||
"AI agents can now autonomously negotiate, authorize, and process payments within strict, " +
|
||||
"human-defined budget limits. Amazon Bedrock AgentCore Payments implements this through a " +
|
||||
"layered architecture: PaymentManager → PaymentConnector → PaymentInstrument → PaymentSession.",
|
||||
}),
|
||||
|
||||
+1
@@ -3,6 +3,7 @@
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<meta name="description" content="Demo content provider for Amazon Bedrock AgentCore Payments x402 paywall use case. An AI agent pays for and unlocks premium content using USDC on Base Sepolia testnet." />
|
||||
<title>AgentCore Payments — Demo Content Provider</title>
|
||||
<style>
|
||||
body { font-family: system-ui, sans-serif; max-width: 760px; margin: 48px auto; padding: 0 24px; color: #1a1a1a; }
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
TODO
|
||||
Reference in New Issue
Block a user