Author: Chris Wajule and Simon Goldberg
Disclaimer: This is a sample and reference implementation intended for demonstration, learning, and prototyping. It is not production-ready as shipped and is provided without warranty. It runs entirely on test networks (Base Sepolia and Solana Devnet) with test-only USDC and no real funds move. Before any production use you must conduct your own security, privacy, compliance, and reliability review, scope all IAM policies to least privilege for your environment, and validate the solution against your organization's requirements. Amazon Bedrock AgentCore payments is a preview capability and its APIs may change. Nothing here is legal, financial, or compliance advice.
This solution shows how to build pay-per-use AI services with Amazon Bedrock AgentCore payments and the open x402 payment protocol. Users sign in through Amazon Cognito, provision an embedded crypto wallet backed by either Coinbase CDP or Stripe/Privy as the credential provider, grant the agent a scoped spending session, and then chat with a voice and text agent (Anthropic Claude Sonnet for text and Amazon Nova Sonic for voice, built on the Strands Agents framework). The agent pays x402 sellers, an AI image generator powered by Amazon Nova Canvas and an agent-economy storefront, settling USDC on Base Sepolia or Solana Devnet through the Amazon Bedrock AgentCore payments ProcessPayment API, with the x402 facilitator verifying signatures and posting settlements on-chain. The AgentCorePaymentsPlugin is the canonical payment path: it intercepts each HTTP 402 and runs ProcessPayment automatically, so the agent never assembles a payment by hand. Administrators manage the AgentCore payments control plane from the included admin surface (creating and rotating credential providers, payment managers, and connectors for both vendors, and provisioning the storefront seller's payout wallet), while the storefront itself originates refunds as the payer. The patterns map directly to ecommerce, retail, and digital-asset use cases: an autonomous buyer paying per request, a storefront that sells physical and digital goods and issues refunds, and a seller that monetizes content and AI generation. Together the user surface, agent runtime, and seller endpoints provide an end-to-end reference for teams building agents that transact on behalf of users.
- Features
- Architecture
- Architecture Details
- Deployment
- Using the Platform
- Development and Testing
- Clean Up
- Troubleshooting
Autonomous payments
AgentCorePaymentsPluginas the canonical payer: it intercepts each HTTP 402, runsProcessPayment, and retries with the signed proof, so the agent never assembles a payment by hand.- End-to-end x402: 402 terms, verify, and settle through the x402 facilitator, with on-chain USDC.
- Multi-network: Base Sepolia (EVM, EIP-3009) and Solana Devnet (SPL token transfer, gasless via the facilitator feePayer).
- Payment sessions with a USDC spending limit and a 15 to 480 minute expiry that cap everything the agent can spend.
Conversational agent
- Text mode (Anthropic Claude Sonnet) and voice mode (Amazon Nova Sonic) over a direct WebSocket to Amazon Bedrock AgentCore Runtime, on the Strands Agents framework, with a REST
/invocationsfallback for text-only callers. - Six tools:
check_balance,list_products,buy_product,generate_image,list_orders,cancel_order. - Streaming responses with live tool-use status and media events, a fresh AgentCore Memory session per connection, and a
context_updatemessage to switch instrument, session, or network without reconnecting.
Wallets and credential providers (two vendors)
- Coinbase CDP (email-OTP end-user UUID plus delegation) and Stripe/Privy (server-provisioned wallet plus a Connect Agent session-signer attach).
- Instrument lifecycle: create, list, get, balance (
GetPaymentInstrumentBalance), and soft delete. - Admin control plane for credential providers (create, rotate, delete), payment managers, and connectors, plus a one-pass Quick Setup.
Agent-economy storefront (seller)
- Product catalog with atomic inventory (no overselling), seeded at deploy.
- x402 orders with strict verify, reserve, settle, fulfil ordering and nonce idempotency, so goods ship only after settlement.
- Fulfilment by type: digital file (tracked, download-once, non-refundable after download), license token (HMAC-signed), and physical good (Amazon SES confirmation email with a graceful preview fallback).
- Per-buyer Library and Orders history backed by Amazon S3 and Amazon DynamoDB.
- An AgentCore-provisioned seller payout wallet shared by the storefront and the image generator.
Image generation (seller)
- Amazon Nova Canvas behind x402; the image returns through the gateway and the agent stores it (a 30-minute media link plus a durable library copy). The base64 never enters the model context.
Refunds (seller as payer)
- A consume-gated, agent-callable refund plus an admin force-refund, each through a per-refund spend-capped session, with inventory restock and library cleanup on success.
Security and operations
- Amazon Cognito JWT authorizer plus in-Lambda admin-group checks; the x402 proof is the seller API authentication.
- Secrets held in AWS Secrets Manager through the AgentCore Token Vault; no keys in the frontend.
- AgentCore Observability (ADOT tracing) and vended Amazon CloudWatch Logs delivery per payment manager.
- One-command deploy and teardown, including an account-scoped sweep of runtime payment resources.
The solution has two sides. The buyer side (main diagram) is an Admin Flow that configures payment infrastructure once on the control plane and a User Flow where the agent discovers and pays for services on the data plane. The seller side (seller diagram) provisions the storefront seller and serves paid requests: image generation, storefront orders, and refunds. Sellers are a black box in the main diagram and are broken out in the seller diagram.
The numbered steps trace each arrow in the diagram, grouped by phase.
Authentication
- Sign in (user to AWS Amplify). The user opens the React frontend on AWS Amplify and starts a sign-in.
- Token issue (Amplify to Amazon Cognito). Cognito authenticates the user and issues a JWT. The API client then attaches the Cognito ID token as a Bearer header on every call to Amazon API Gateway, where a JWT authorizer validates it. Admin pages additionally require the
admingroup, enforced in-Lambda withrequire_admin.
Admin setup: control plane (one-time)
Admin requests flow from Amplify to API Gateway to the admin Lambdas, which call the Amazon Bedrock AgentCore payments control plane (bedrock-agentcore-control).
- CreatePaymentCredentialProvider (API Gateway to the credential-providers Lambda). From the Credential Providers page (or Quick Setup), the Lambda calls
create_payment_credential_provider(). CoinbaseCDP stores the CDP API key ID, API key secret, and wallet secret; StripePrivy stores the Privy app credentials. Vendor secrets live in AWS Secrets Manager; only the secret ARNs return to the UI, and rotation (UpdatePaymentCredentialProvider) preserves the provider ARN so connectors and instruments keep working. - CreatePaymentManager (API Gateway to the managers Lambda). The Lambda calls
create_payment_manager(), backed by an IAM service role that AgentCore payments assumes to reach the Token Vault and sign payments. - CreatePaymentConnector (API Gateway to the connectors Lambda). The Lambda calls
create_payment_connector()to bind a manager to a credential provider; the connectortypematches the provider vendor. Quick Setup runs steps 3 to 5 in one pass per vendor. - Control plane execution (admin Lambdas to AgentCore payments). The
create_*calls run againstbedrock-agentcore-control, which provisions the credential provider, manager, and connector and stores the vendor secrets in Secrets Manager through the Token Vault.
User setup: data plane
User requests flow from API Gateway to the user Lambdas, which call the AgentCore payments data plane (bedrock-agentcore). Non-admin users discover the manager ARN and connector through the read-only /user/payment-options endpoint.
- CreatePaymentInstrument (API Gateway to the instruments Lambda). The Instruments page calls
create_payment_instrument()to register an embedded crypto wallet forETHEREUM(Base Sepolia) orSOLANA(Solana Devnet), linked to the manager and connector. Coinbase instruments capture the user's CDP end-user UUID from an email OTP and forward it as theuserId; for Privy instruments the user opens the Connect Agent page and attaches the AgentCore payments authorization-key quorum as a session signer (addSessionSigners) across their Privy wallets. - CreatePaymentSession (API Gateway to the sessions Lambda). The Sessions page (or New Payment Session in chat) calls
create_payment_session()with a USDCmaxSpendAmountand a 15 to 480 minute expiry. The session caps everything the agent can spend. - Discovery (API Gateway to the payment-options Lambda). A read-only
list_payment_managersandlist_payment_connectorslets non-admin users find the manager ARN and connector they need for steps 7 and 8. - Data plane execution (user Lambdas to AgentCore payments). Instrument, session, and balance calls run against
bedrock-agentcore; the Instruments page reads live balances throughGetPaymentInstrumentBalance.
Conversation
- WebSocket URL (Amplify to the ws_url Lambda). The chat page requests a presigned WebSocket URL.
- Mint WSS (ws_url Lambda to AgentCore Runtime). The Lambda calls
InvokeAgentRuntimeWithWebsocketStreamto mint a SigV4-signed WSS URL and returns it with the session id. - Stream (Amplify to Amazon Bedrock AgentCore Runtime). The browser connects directly over WSS and sends an init frame with the payment context (
userId,managerArn,instrumentId,sessionId,connectorId,network,mode), then messages. The Payer Agent runs on Anthropic Claude Sonnet for text (with theAgentCorePaymentsPluginattached) and Amazon Nova Sonic for voice, on Strands Agents, and selects a tool:check_balance,list_products,buy_product,generate_image,list_orders, orcancel_order. Acontext_updatemessage can switch instrument, session, or network without reconnecting. - Memory (Runtime to AgentCore Memory). A fresh per-connection session is created in AgentCore Memory; the agent loads and saves conversation state there so text and voice share history.
- Observability (Runtime to AgentCore Observability). ADOT auto-instrumentation emits traces and payment spans, and vended Amazon CloudWatch Logs delivery routes each payment manager's transaction logs to a log group.
Payment
- Initial x402 request (Runtime to Paid Resources). A paid tool (
generate_imageorbuy_product) sends its first request to the seller without a proof and receives HTTP 402 with the payment terms: price in USDC, the seller payTo address, the facilitator URL, and the supported networks. - ProcessPayment and settle (Runtime to AgentCore payments). The
AgentCorePaymentsPluginintercepts the 402 and calls AgentCore paymentsProcessPayment, which signs the payload through the Token Vault (EIP-3009 for EVM, SPL token transfer for Solana) and returns a proof (PROOF_GENERATED). The plugin retries with thePAYMENT-SIGNATUREheader; the seller verifies and settles through the x402 facilitator, which posts the on-chain USDC transfer. - Library and orders (API Gateway to the storefront_library Lambda). The Library and Orders pages read the buyer's purchases from the Orders table in Amazon DynamoDB (via the
buyerUserIdindex) and the library bucket in Amazon S3.
Agent build pipeline (deploy time)
- Build and run (Agent Deploy to AgentCore Runtime). AWS CDK uploads the agent source to Amazon S3; a custom-resource Lambda starts an AWS CodeBuild project that builds the container image and pushes it to Amazon Elastic Container Registry (Amazon ECR); AgentCore Runtime runs that image.
The seller diagram has four panels. Each panel's numbered flow is below.
- Seller Setup. The admin Seller Setup page calls
POST /admin/storefront/seller/setup(main Cognito API, behindrequire_admin), routing to the seller-setup Lambda. - Provision AgentCore payments resources. The Lambda calls the AgentCore payments APIs in order:
create_payment_credential_provider()(Coinbase CDP),create_payment_manager()(AWS_IAM service role),create_payment_connector(), andcreate_payment_instrument()twice, one Base Sepolia and one Solana Devnet payout instrument, both scoped to the seller serviceuserId. - Persist config. The Lambda writes the seller config (manager, connector, credential-provider ids, both payout addresses, status
READY) to Amazon DynamoDB and returns the Coinbase Wallet Hub delegation links plus a one-time Solana USDC funding note. The image generator and the storefront both read their payout address from this single config.
- Browse.
list_productscallsGET /products→ the products Lambda → the catalog in Amazon DynamoDB (free, no payment). - Order and 402.
buy_productcallsPOST /orderswithout a proof → the orders Lambda returns HTTP 402 with the payTo from the seller config. - Pay. The
AgentCorePaymentsPluginrunsProcessPaymentfrom the buyer's session and retries/orderswith the proof. - Verify, settle, fulfil. The orders Lambda runs the order in strict order: verify the proof, reserve inventory atomically in DynamoDB, settle through the x402 facilitator, then fulfil by type: a digital file copied to the Amazon S3 library bucket (tracked download), a signed license token, or a physical-order email, then mark the order
CONFIRMED. Goods are delivered only after settlement succeeds.
- Request and 402.
generate_imagecallsPOST /image-genwithout a proof → the image-gen Lambda reads its payout address from the seller config (DynamoDB) and returns HTTP 402. - Pay. The plugin runs
ProcessPaymentfrom the buyer's session and retries with the proof. - Generate. On settlement the Lambda calls Amazon Bedrock (Nova Canvas) to render the PNG and returns it as base64 through API Gateway to AgentCore Runtime.
- Store and deliver. The agent runtime uploads the image to the Amazon S3 media bucket (a 30-minute presigned link) and a durable copy to the per-buyer library bucket, then sends a media event to the frontend. The base64 never enters the model context.
- Find and initiate. When the buyer lacks the order id, the agent looks it up with
list_orders(a buyer-scopedGET /orders?userId=lookup via thebuyerUserIdindex), confirms the match, thencancel_ordercallsPOST /orders/{id}/refund(consume-gated, so a downloaded item is non-refundable and the agent cannot force it; an admin can force viaPOST /admin/storefront/orders/{id}/refundfrom the Seller Orders page). - Capped session. The orders Lambda's
refundOrdercallssettlePayout, which creates a per-refund payment session capped at exactly the refund amount, scoped to the selleruserId. - Pay the buyer. It calls
ProcessPaymentwith the seller's instrument for the order's network as the payer, then settles seller→buyer through the x402 facilitator. - Finalize. On a successful settle the order is marked
REFUNDED, inventory is restocked, and the buyer's library copy is removed.
Every paid action converges on the AgentCore payments ProcessPayment call, driven by the AgentCorePaymentsPlugin.
| Path | Tool | Price | How it works |
|---|---|---|---|
| Image generation | generate_image |
0.04 USDC | The seller Lambda returns HTTP 402; the plugin runs ProcessPayment and retries with the proof; the seller settles and renders the image with Amazon Nova Canvas |
| Storefront order | buy_product |
per product | The storefront returns HTTP 402; the plugin pays; the order Lambda verifies, reserves inventory, settles, and fulfils |
| Refund | cancel_order |
reverse | The order Lambda creates a per-refund spend-capped session and calls ProcessPayment with the seller as the payer, settling USDC back to the buyer |
| Balance | check_balance |
free | GetPaymentInstrumentBalance on the active instrument; no payment |
| Order lookup | list_orders |
free | Buyer-scoped GET /orders?userId= on the storefront (via the buyerUserId index); lets the agent find an order id to refund across sessions |
Canonical plugin path: In text and REST modes the AgentCorePaymentsPlugin is attached to the agent. A paid tool issues its first request with no proof; on an HTTP 402 it returns a PAYMENT_REQUIRED marker that the plugin intercepts, running the tagged ProcessPayment and retrying the tool with the PAYMENT-SIGNATURE header injected. The agent never assembles a payment by hand, and the base64 image never enters the model context. Voice mode (BidiAgent) uses an equivalent in-tool pay-and-retry fallback. Both paths call the same ProcessPayment with the session ID, instrument ID, the payment requirements from the 402, and the vendor-matched userId.
Payment credentials (manager ARN, instrument ID, session ID, wallet address, network, and the vendor-matched userId) are threaded to the agent per session through the WebSocket init frame (or the REST body), so the agent does not read a database at connection time. The agent injects them into the tool layer through set_payment_credentials(). For Coinbase instruments the CDP UUID is the effective userId; for Stripe/Privy instruments the Cognito sub is used. The network field (ETHEREUM or SOLANA) selects the x402 scheme and the balance lookup. A context_update message lets the frontend switch instrument, session, or network without reconnecting.
| Mode | Model | Payment path |
|---|---|---|
| Text | Anthropic Claude Sonnet (us.anthropic.claude-sonnet-4-6) via Strands Agents |
AgentCorePaymentsPlugin (canonical) |
| Voice | Amazon Nova Sonic (amazon.nova-2-sonic-v1:0) via BidiAgent |
in-tool pay-and-retry fallback |
Both modes share the same tools and payment infrastructure. AgentCore Memory persists conversation across sessions.
The x402-enabled seller endpoints run as Lambda functions behind their own API Gateways. The x402 payment proof is the authentication, so no Cognito is required. Both accept Base Sepolia and Solana Devnet and resolve their payout address from the provisioned seller config.
| Endpoint | Function | Price | Response |
|---|---|---|---|
POST /image-gen |
AI image generation via Amazon Nova Canvas | 0.04 USDC | Base64-encoded PNG, returned to the agent, which stores it in Amazon S3 |
POST /orders |
Agent-economy storefront order (verify → reserve inventory → settle → fulfil) | per product | Order confirmation; digital file/license or physical-order email |
GET /products |
Storefront catalog (free, no payment) | n/a | Product list/detail from Amazon DynamoDB |
The storefront also exposes POST /orders/{id}/refund (consume-gated, agent-callable) and, on the main authenticated API, an admin force-refund. A refund makes the seller the payer through a per-refund spend-capped session.
- AWS account with appropriate permissions
- Node.js 18.x or later
- AWS CDK CLI, pinned (
npm install -g aws-cdk@2.1128.1) - AWS CLI configured with credentials
- Python 3.12 (for local agent development)
- A wallet provider account: Coinbase CDP or Stripe via Privy. See Obtaining Wallet Provider Credentials for step-by-step instructions and links.
- USDC on Base Sepolia or Solana Devnet for testing, from the Circle Faucet
- Bash shell (Windows: use WSL or Git Bash)
The setup scripts handle everything from a clean clone: .env creation, dependency installation, CDK bootstrap, deployment, and automatic .env injection of stack outputs.
Move into the project directory:
cd agentcore-paymentsCreate your .env from the template:
cp .env-sample .envOptional: if you plan to use Stripe/Privy wallets, open .env and fill in the two public Privy IDs (VITE_PRIVY_APP_ID and VITE_PRIVY_SIGNER_ID) from the Privy Dashboard. These are the only values you set by hand; everything else is auto-detected or injected by the setup scripts. You can skip this and add them later if you are only using Coinbase CDP. See Obtaining Wallet Provider Credentials for where to find them.
Deploy the backend (installs dependencies, deploys the CDK stack, and injects outputs):
npm run setup:backendDeploy the frontend:
npm run setup:amplifyThere is no seller wallet to set in .env. The seller's payout wallet (EVM and
Solana) is provisioned by AgentCore payments from the admin Seller Setup page
after deploy, and every paid endpoint (storefront orders and the image-gen
seller) receives payments to that one provisioned wallet.
setup:backend:
- Copies
.env-sample→.envif missing. - Detects
AWS_ACCOUNT_IDandAWS_REGIONfrom your CLI config. - Installs all npm dependencies (backend CDK and seller Lambdas).
- Bootstraps CDK.
- Deploys the CDK stack.
- Injects stack outputs (
COGNITO_USER_POOL_ID,API_URL,SELLER_API_URL,MEMORY_ID, and theirVITE_-prefixed counterparts) into.env.
setup:amplify:
- Builds the React frontend with the injected env vars.
- Creates an Amplify app on first run or reuses the existing one on subsequent runs.
- Deploys the build artifacts and saves
AMPLIFY_APP_IDto.env.
Re-running setup:amplify updates the same deployment; it never creates duplicates.
StripePrivy-backed wallets require attaching the AgentCore authorization-key quorum as a session signer before ProcessPayment can sign on the user's behalf. The Instruments page exposes an Add Signer action per Privy instrument that runs a one-time Privy email OTP and then calls addSessionSigners. To enable the flow, set two public values in .env:
| Variable | Source |
|---|---|
VITE_PRIVY_APP_ID |
Privy Dashboard → App → App ID |
VITE_PRIVY_SIGNER_ID |
Privy Dashboard → Wallet infrastructure → Authorization keys → key ID |
Both values are public identifiers; the private key and app secret stay on the backend and are entered directly in the admin surface (Credential Providers page).
Important — the signer and the credential provider must use the same authorization key.
VITE_PRIVY_SIGNER_IDmust be the same Privy authorization key whose private key you later paste as the Credential Provider's Authorization Private Key — i.e. the credential provider's Authorization Key ID must equalVITE_PRIVY_SIGNER_ID. The Add Signer flow grants your wallet delegation toVITE_PRIVY_SIGNER_ID, and the agent signs with the credential provider's key; if they are different keys,ProcessPaymentwill be rejected by Privy at signing time even though everything appears configured.
If you prefer to deploy step by step:
cp .env-sample .envThe setup script auto-detects or injects every value; there is nothing to fill in manually. The seller payout wallet is provisioned later from the admin Seller Setup page, not set here.
| Variable | Required | Source |
|---|---|---|
AWS_REGION |
No | AWS CLI config |
AWS_ACCOUNT_ID |
No | aws sts get-caller-identity |
CP_ENDPOINT / DP_ENDPOINT |
No | Derived from AWS_REGION |
COGNITO_USER_POOL_ID |
No | Injected by setup:backend |
COGNITO_CLIENT_ID |
No | Injected by setup:backend |
API_URL |
No | Injected by setup:backend |
SELLER_API_URL |
No | Injected by setup:backend |
MEMORY_ID |
No | Injected by setup:backend |
VITE_PRIVY_APP_ID |
No | Privy Dashboard (only needed for StripePrivy Add Signer flow) |
VITE_PRIVY_SIGNER_ID |
No | Privy Dashboard (only needed for StripePrivy Add Signer flow) |
After deploy, run Seller Setup from the admin page to provision the seller payout wallet. The setup page surfaces the Solana payout address with funding guidance: fund it once with USDC on Solana Devnet through the Circle Faucet so its token account exists, which the x402 facilitator needs to settle Solana payments. EVM needs no such step.
Install the backend (CDK) dependencies:
cd backend && npm ci && cd ..Install the image generation seller dependencies:
cd backend/lambdas/sellers/image-gen && npm ci && cd ../../../..Install the storefront seller dependencies:
cd backend/lambdas/sellers/storefront && npm ci && cd ../../../..Install the frontend dependencies:
cd frontend && npm ci && cd ..Bootstrap CDK (first time per account and Region):
cd backend && npm run cdk -- bootstrap "aws://$AWS_ACCOUNT_ID/$AWS_REGION"Deploy the stack:
npm run cdk -- deploy --require-approval never --outputs-file ../cdk-outputs.jsonCopy the values from cdk-outputs.json into .env, or run setup:backend, which does this automatically.
npm run setup:amplifyOr run the frontend locally:
cd frontend && npm run dev-
Sign in as an admin.
setup:backendseeds a demo admin user (demo@agentcore-payments.dev) in theadmingroup, so you can reach the admin pages immediately. The password is generated once during deployment and stored in AWS Secrets Manager (never in this repo, logs, or stack outputs). Retrieve it using the secret name from theAdminCredentialsSecretNamestack output, whichsetup:backendalso injects into.envasADMIN_SECRET_NAME:aws secretsmanager get-secret-value --secret-id "$ADMIN_SECRET_NAME" --query SecretString --output textRotate or remove this demo account before any real exposure. Otherwise, sign up your own account (the first user is auto-assigned to the
usergroup) and add it to theadmingroup in the Cognito console. -
Quick Setup (recommended): From the Admin > Overview page, click Quick Setup and pick a vendor tab (Coinbase CDP or Stripe/Privy). Fill in the vendor credentials and a manager and connector name. The UI runs all three create calls in order. See Obtaining Wallet Provider Credentials for how to get each vendor's values.
-
Manual setup (for finer control or adding a second vendor):
- Credential Provider: Admin > Credential Providers > Create. Coinbase CDP takes the API Key ID, API Key Secret, and Wallet Secret. Stripe/Privy takes the App ID, App Secret, Authorization Key ID, and P256 Authorization Private Key.
- Payment Manager: Admin > Payment Managers > Create. Only a name and optional description are required; the IAM role is provisioned by the stack.
- Payment Connector: Admin > Payment Connectors > Create. Pick the manager and credential provider; the
typeis inferred from the provider vendor.
-
Editing and rotating:
- Payment Managers and Payment Connectors support editing the description after creation. Names and ARNs are immutable by the service.
- Credential Providers support credential rotation through the Edit action.
UpdatePaymentCredentialProvideris a full replace ofproviderConfigurationInput, so the dialog resubmits the full secret set for the chosen vendor. The provider ARN stays the same, so connectors and instruments continue to work without migration.
-
Create an Instrument: Navigate to Instruments. Pick a network (
ETHEREUMfor Base Sepolia orSOLANAfor Solana Devnet), select a connector, and click Create.- Coinbase CDP instruments: The page prompts for a Coinbase email OTP to capture your CDP end-user UUID. The wallet, delegation, and all downstream calls address the same CDP user.
- Stripe/Privy instruments: AgentCore provisions the wallet server-side. Click Add Signer on the instrument row to attach the agent's authorization-key quorum through a one-time Privy email OTP. The row displays Signer ✓ once attached. See the Privy add-signers docs for the underlying flow.
-
Grant signing permission (Coinbase only): Click Grant Delegation on the Instruments page to authorize AgentCore to sign x402 payments on your behalf for 24 hours. Revoke at any time.
-
Create a Payment Session: In the Agent Chat page, click New Payment Session. Set a spending limit (for example, 1.0 USD) and expiry (15 to 480 minutes). Sessions are network-agnostic, so the same session works with any instrument under the selected payment manager.
-
Select your wallet from the dropdown in the chat header. The network is detected from the instrument.
-
Fund your wallet with USDC from the Circle Faucet: pick Base Sepolia for EVM instruments or Solana Devnet for Solana instruments.
-
Connect: Click Text for text mode or Voice for voice mode.
-
Chat with the agent:
- Image generation: "Generate an image of a sunset over mountains"
- Browse the storefront: "What's for sale?"
- Buy a product: "Buy the stock photo pack"
- Cancel and refund: "Cancel my last order"
- Wallet balance: "What's my wallet balance?"
User: What's my wallet balance?
Agent: [check_balance]
Your wallet has 4.85 USDC on Base Sepolia.
User: What's for sale?
Agent: [list_products]
Here is each product with its price, stock, and description...
User: Buy the stock photo pack
Agent: [buy_product]
Your Stock Photo Pack purchase is confirmed, 7.99 USDC on Solana Devnet.
It's available in your Library.
User: Generate an image of a whale swimming in space
Agent: [generate_image]
Your image is ready, 0.04 USDC. It's shown here and saved to your Library.
User: Cancel that order
Agent: [cancel_order]
The order was cancelled and 7.99 USDC was refunded to your wallet.
User: (new session) Actually, refund the stock photo pack I bought earlier
Agent: [list_orders]
I found your Stock Photo Pack order for 7.99 USDC on Solana Devnet.
[cancel_order]
Done, 7.99 USDC was refunded to your wallet.
Install dependencies:
cd payment-agent && pip install -r requirements.txtRun the agent:
python agent.pyThe agent runs on port 8080 with /ping, /health, /invocations (REST), and /ws (WebSocket) endpoints.
curl -X POST http://localhost:8080/invocations \
-H "Content-Type: application/json" \
-d '{"prompt": "What is for sale in the storefront?", "userId": "test-user"}'Install dependencies and start the dev server:
cd frontend && npm ci && npm run devBuild for production:
npm run buildThe React frontend uses Vite and connects to the API Gateway URL in VITE_API_URL.
Install dependencies:
cd backend && npm ciSynthesize the CloudFormation template:
npm run cdk -- synthPreview changes against the deployed stack:
npm run cdk -- diffDeploy:
npm run cdk -- deployagentcore-payments/
├── payment-agent/ # Agent container (deployed to AgentCore Runtime)
│ ├── agent.py # FastAPI server, text/voice streaming, WebSocket handler
│ ├── tools.py # check_balance, generate_image, list_products, buy_product,
│ │ # list_orders, cancel_order; x402 + AgentCore payments ProcessPayment
│ ├── config.py # Centralized environment configuration
│ ├── Dockerfile # Python 3.12 slim container
│ └── requirements.txt # strands-agents, bedrock-agentcore (Payments plugin), fastapi, boto3
├── backend/
│ ├── lib/
│ │ └── payment-agent-stack.ts # CDK stack (Cognito, DynamoDB, Lambda, API GW, ECR,
│ │ # CodeBuild, AgentCore Runtime + Memory, S3)
│ └── lambdas/
│ ├── admin/ # Credential providers, payment managers, payment connectors
│ ├── user/ # Instruments, sessions, payment options, agent WebSocket URL
│ ├── sellers/
│ │ ├── image-gen/ # x402 seller: Nova Canvas image generation (0.04 USDC)
│ │ └── storefront/ # x402 agent-economy storefront: products, orders (x402 +
│ │ # refunds), seller setup, library; deliverables + static site
│ └── shared/ # AgentCore payments client, response helpers
├── frontend/
│ └── src/
│ ├── pages/
│ │ ├── admin/ # Overview, credential providers, managers, connectors,
│ │ │ # seller setup, seller orders, how it works
│ │ └── user/ # Connect agent, agent chat, instruments, sessions,
│ │ # orders, library, information
│ ├── components/ # Reusable UI components
│ ├── providers/ # PrivyProvider (Privy embedded wallets)
│ └── lib/ # API client, auth, balance utilities
├── test/integration/ # setup_backend.sh, setup_amplify.sh, cleanup.sh,
│ # delete_payment_resources.py
├── .env-sample # Environment variable template
├── package.json # Top-level scripts (setup, cleanup)
└── amplify.yml # AWS Amplify build configuration
npm run cleanupThis deletes the Amplify app (from the saved AMPLIFY_APP_ID), runs an account-scoped teardown of the runtime AgentCore payments resources created via the admin console and Seller Setup (managers, connectors, credential providers, instruments, sessions), destroys the CDK stack, removes CloudWatch log groups, cleans the Amazon ECR repository, and deletes local build artifacts. It prompts for confirmation, with a separate confirmation for the account-wide payment resource sweep (skip that step if you run cleanup in a shared account).
Delete resources in reverse order of creation.
1. Delete the Amplify app:
APP_ID=$(aws amplify list-apps --query "apps[?name=='agentcore-payments'].appId" --output text)
aws amplify delete-app --app-id $APP_ID2. Delete the runtime AgentCore payments resources (managers, connectors, credential providers, instruments, sessions) created via the admin console and Seller Setup. These are not part of the CDK stack, so do this before destroying the stack:
python3 test/integration/delete_payment_resources.py --yes3. Destroy the CDK stack:
cd backend && npm run cdk -- destroy --force && cd ..4. Delete CloudWatch log groups:
for prefix in "/aws/lambda/agentcore-payments" "/aws/lambda/x402-seller" "/aws/lambda/x402-storefront" "/aws/codebuild/agentcore-payments" "/aws/bedrock-agentcore/runtimes"; do
aws logs describe-log-groups --log-group-name-prefix "$prefix" \
--query 'logGroups[*].logGroupName' --output text | \
xargs -n1 aws logs delete-log-group --log-group-name 2>/dev/null
done5. Delete ECR images:
aws ecr delete-repository --repository-name agentcore-payments-agent --force6. Remove local files:
rm -rf backend/node_modules/ backend/cdk.out/ frontend/node_modules/ frontend/dist/| Issue | Cause | Solution |
|---|---|---|
401 Unauthorized on API calls |
Cognito token expired or missing | Log out and log back in; verify VITE_COGNITO_USER_POOL_ID and VITE_COGNITO_CLIENT_ID match CDK outputs |
403 Forbidden on admin routes |
User not in admin group |
Add the user to the admin group in the Cognito console |
Payment session expired |
Session exceeded its expiry | Create a new session (15–480 minutes) |
Insufficient balance |
Session spending limit reached | Create a new session with a higher USDC spending limit |
Payment instrument not found on Coinbase |
Instrument created before the CDP UUID identity fix, or a stale session created under a different identity | Recreate the Coinbase instrument and create a fresh session |
ProcessPayment succeeds but transfer fails on Privy |
Authorization-key quorum is not attached as a signer on the wallet | Click Add Signer on the Privy instrument row and complete the Privy email OTP |
Solana payments fail with empty {} error |
The provisioned seller wallet has no USDC token account on devnet | Fund the seller's Solana payout address (shown on the admin Seller Setup page) with USDC through the Circle Faucet on Solana Devnet |
| Solana payments fail, wrong network selected | Agent picks EVM accept instead of Solana | Rebuild the agent container (npm run setup:backend). The seller session registers only the user's active network |
| Agent not responding | AgentCore Runtime not deployed or unhealthy | Check that AgentRuntimeArn exists; verify the CodeBuild project succeeded |
| Images not displaying | S3 presigned URL expired or media bucket missing | URLs expire after 30 minutes; verify MEDIA_BUCKET on the Runtime |
| Voice mode no audio | Nova Sonic not enabled | Enable amazon.nova-2-sonic-v1:0 in the Bedrock console for your region |
| WebSocket disconnects on large responses | 128 KB frame limit | Large responses chunk automatically; this is an API Gateway limit |
| CDK deploy fails on CodeBuild | Docker not available or ECR permissions missing | Ensure the CodeBuild project has privileged: true and ECR push permissions |
ModuleNotFoundError in agent |
Missing dependency in container | Verify requirements.txt includes all packages; redeploy through cdk deploy |
- Wallet private keys are stored in AWS Secrets Manager through the AgentCore Token Vault and never reach the agent or frontend.
- API routes are protected by Cognito JWT authorization.
- Seller endpoints use x402 payment proofs as authentication; no API keys needed.
- The S3 media bucket blocks public access; content is served through time-limited presigned URLs.
- Payment sessions have configurable spending limits and expiry durations that limit exposure.
- For Coinbase-backed wallets, AgentCore signs on the user's behalf only while the user's CDP delegation is active, scoped to 24 hours by default and revocable at any time.
- For Privy-backed wallets, the agent signs through the authorization-key quorum attached through Add Signer. Signer attachment is one-time per wallet and revocable through the Privy dashboard.
- The seeded demo admin password is generated at deployment and stored in AWS Secrets Manager, not in this repository. Retrieve it from Secrets Manager (see Using the Platform) and rotate or remove the account before any real exposure.
The CDK app runs cdk-nag AwsSolutionsChecks on every synth and deploy, so infrastructure is linted against the AWS Solutions rule pack. Genuine improvements are applied in the stack (S3 enforceSSL, DynamoDB point-in-time recovery, and CloudFront origin access control). The remaining findings are intentional sample trade-offs (for example, x402 seller APIs use payment proofs instead of a JWT authorizer, and AgentCore payments preview actions are not yet resource-scopeable) and carry inline NagSuppressions with a documented reason for each. Run CDK_NAG=0 npm run cdk -- synth to skip the checks during fast local iteration.
This sample runs a conversational agent that can take actions on a user's behalf, including test-network payments. It is built with responsible AI safeguards, and you should extend them for production:
- Bounded authority. The agent can only spend within an explicit payment session that carries a user-set USDC spending limit and a 15 to 480 minute expiry. It cannot exceed the limit or act after expiry, and the session is created by the user, not the model.
- Scoped identity. Each paid action is bound to the user's own instrument and vendor-matched
userId, injected server-side into the tool layer. The model does not choose whose funds to spend. - Test-only funds. All payments settle in test-network USDC (Base Sepolia, Solana Devnet). No real money moves.
- Human in the loop. The user initiates each conversation, sees live tool-use status for every action (browsing, purchasing, refunding), and can stop at any time. Refunds of real value should keep an explicit human approval step.
- Managed models. All model access is through Amazon Bedrock (Anthropic Claude Sonnet for text, Amazon Nova Sonic for voice, Amazon Nova Canvas for images). For production, configure Amazon Bedrock Guardrails for content filtering and denied topics, add validation of tool inputs and model outputs, and log agent decisions for auditability.
- Transparency. The agent identifies itself as an AI assistant and does not impersonate a human.
Deploying an autonomous agent that transacts on a user's behalf is a high-responsibility use case. Review the AWS Responsible AI guidance and apply controls appropriate to your risk tolerance before moving beyond test networks.
This sample does not process or store cardholder data. Payments are settled in stablecoin (USDC) over the x402 protocol using wallet signatures, and Stripe/Privy is used here as a wallet credential provider, not as a card processor, so PCI-DSS does not apply to this implementation. If you extend this solution to accept card payments, you become responsible for PCI-DSS compliance; see the AWS PCI-DSS compliance resources for guidance. Nothing here is legal or compliance advice.
This library is licensed under the MIT-0 License. See the LICENSE file.

