All skills
aws avatar

/agents-pay

@9766f27

Use when THIS agent needs to pay for x402-protected content at runtime: hitting a paywall mid-task, settling it via AgentCore Payments, and applying operator-defined spend limits. Covers payment setup, policy, session budgets, and troubleshooting. Triggers on: "my agent hit a 402 while calling an API", "a tool call returned 402 Payment Required", "my agent needs to pay for x402-protected content", "let the agent pay for content, capped at $5 per session", "set a spend limit for the agent", "ProcessPayment failed", or "why did my agent refuse to pay". Not for BUILDING payment capability for end users, including wallets and framework middleware; use agents-build and references/payments.md. For non-paid APIs via Gateway use agents-connect. For inbound auth use agents-harden. For project scaffolding use agents-get-started.

Use this Skill: https://skilld.dev/gh/aws/agent-toolkit-for-aws/agents-pay

This session only. Nothing lands on disk.

referencessetup.md

≈3.3k tokens on demand. Your agent reads this file only when SKILL.md points to it.

agents-pay setup

Full provisioning walkthrough. A human runs every step here except the final wiring. See the tool inventory in SKILL.md for what the agent can call.

0. Install

python3 -m venv .venv
source .venv/bin/activate
python -m pip install -r requirements.txt
npm install -g @aws/agentcore
agentcore --version
python -c "from bedrock_agentcore.payments import PaymentManager; print('payments OK')"

If that import fails, install a bedrock-agentcore release with payments support before continuing. Keep the virtual environment active for the Python commands below.

requirements.txt pins the complete Python runtime graph used by this skill. For integrity pinning in your own release process, generate platform-specific hashes from that exact graph:

python -m pip download -r requirements.txt -d wheels/
python -m pip hash wheels/*

1. Obtain provider credentials

Do this before running the connector command. Never paste these into a chat, an agent prompt, or a command flag.

Coinbase CDP — https://portal.cdp.coinbase.com/

  1. Create or open a CDP project
  2. Create an API key — note the API Key ID and API Key Secret
  3. Generate a Wallet Secret (used for signing operations)
  4. Project → Wallet → Embedded Wallets → Policies → enable Delegated signing (required)

Stripe Privy — https://dashboard.privy.io/

  1. Create a dedicated Privy app for AgentCore (do not reuse an existing app)
  2. Copy the App ID and App Secret
  3. Wallet Infrastructure → Authorization → New Key → generate a P-256 key pair
  4. Strip the wallet-auth: prefix from the private key; keep the raw base64 (starts MIGHAgEA...)
  5. Note the Authorization ID

2. Create the payment manager

Leave the LLM conversation and run this in a separate terminal. Do not paste credentials, command output, deployed state, or generated IDs back into chat. Use the bare command so the whole setup stays in the interactive terminal:

agentcore add payment-manager

Names: start with a letter, alphanumeric plus underscores, ≤48 characters.

Optionally tag the project so the service can distinguish skill-onboarded resources — add to the top-level tags object in agentcore/agentcore.json, keeping existing entries:

"tags": { "agentcore:onboarding-source": "agent-toolkit-skill" }

3. Create the payment connector

Run it with no flags. The wizard prompts for each secret, so nothing lands in shell history or the process list:

agentcore add payment-connector

Passing --manager, --name, or --provider switches the CLI to non-interactive mode and then requires every secret as a flag — it will not fall back to prompting. Use the bare command.

The CLI writes provider secrets in plaintext to agentcore/.env.local and uploads them to AgentCore Identity on deploy. Before deploying:

grep -q '^\.env\.local$\|^\.env\.\*$' .gitignore || echo '.env.local' >> .gitignore
chmod 600 agentcore/.env.local

The Python scaffold's default .gitignore lists only .env, so .env.local must be added. The agent must never read this file.

4. Deploy

agentcore deploy

Provisions the manager and connector, plus a Payment<Name>ProcessPaymentRole. IDs land in agentcore/.cli/deployed-state.json under targets.<target>.resources.payments[] (managerArn, connectors[].connectorId, processPaymentRoleArn).

5. IAM: the four-role model

Follow the official guide: https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/payments-iam-roles.html

AgentCore Payments defines four roles. This skill's design assumes them, and the security properties below depend on the separation being real in your account.

Role Purpose Who assumes it
ControlPlaneRole Payment managers, connectors, credential providers Administrator
ManagementRole Payment instruments and sessions. Explicitly denied ProcessPayment The human running this admin CLI
ProcessPaymentRole Executes payments. Cannot create sessions The agent runtime
ResourceRetrievalRole Service role AgentCore assumes to fetch credentials bedrock-agentcore.amazonaws.com

The AWS guide states the reason directly:

"Separating payment management from payment execution prevents a single compromised identity from both creating sessions with unlimited budgets and executing payments against those sessions."

This separation keeps payment management and execution in different trusted roles.

Which role runs which command

Step Command Role
1 agentcore add payment-manager / payment-connector / deploy ControlPlaneRole
2 agents_pay_admin.py init-config none — writes a local file only
3 agents_pay_admin.py create-instrument ManagementRole
4 agents_pay_admin.py new-session ManagementRole
6 the agent calling x402_fetch ProcessPaymentRole

ManagementRole — for the human running the admin CLI

Note the explicit Deny. It is not decoration: it is what stops this role from being usable to both mint budget and spend it.

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "AllowPaymentManagement",
      "Effect": "Allow",
      "Action": [
        "bedrock-agentcore:CreatePaymentInstrument",
        "bedrock-agentcore:GetPaymentInstrument",
        "bedrock-agentcore:ListPaymentInstruments",
        "bedrock-agentcore:DeletePaymentInstrument",
        "bedrock-agentcore:CreatePaymentSession",
        "bedrock-agentcore:GetPaymentSession",
        "bedrock-agentcore:ListPaymentSessions",
        "bedrock-agentcore:DeletePaymentSession"
      ],
      "Resource": [
        "arn:aws:bedrock-agentcore:*:ACCOUNT:payment-manager/*/instrument/*",
        "arn:aws:bedrock-agentcore:*:ACCOUNT:payment-manager/*/session/*"
      ]
    },
    {
      "Sid": "DenyProcessPayment",
      "Effect": "Deny",
      "Action": "bedrock-agentcore:ProcessPayment",
      "Resource": "*"
    }
  ]
}

ProcessPaymentRole — for the agent runtime

ProcessPayment plus reads. No session-write actions.

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "AllowProcessPayment",
      "Effect": "Allow",
      "Action": "bedrock-agentcore:ProcessPayment",
      "Resource": ["arn:aws:bedrock-agentcore:*:ACCOUNT:payment-manager/*/session/*"]
    },
    {
      "Sid": "AllowPaymentReadOperations",
      "Effect": "Allow",
      "Action": [
        "bedrock-agentcore:GetPaymentInstrument",
        "bedrock-agentcore:GetPaymentInstrumentBalance",
        "bedrock-agentcore:GetPaymentSession"
      ],
      "Resource": [
        "arn:aws:bedrock-agentcore:*:ACCOUNT:payment-manager/*/instrument/*",
        "arn:aws:bedrock-agentcore:*:ACCOUNT:payment-manager/*/session/*"
      ]
    }
  ]
}

The AWS guide is emphatic about the combination to avoid:

"Do not include PaymentSession write permissions (for example, CreatePaymentSession) and ProcessPayment in the same role, or the caller can bypass payment limits by creating new sessions with elevated budgets."

Verify after deploy:

aws iam get-role-policy --role-name <ProcessPaymentRole> --policy-name <Policy> \
  | grep -c CreatePaymentSession        # must be 0

A runtime AccessDeniedException on CreatePaymentSession is the control working. Do not "fix" it by granting the permission.

ResourceRetrievalRole

The service role AgentCore assumes at runtime. Created and wired by agentcore deploy; it is not assigned to a human. Its trust policy must name bedrock-agentcore.amazonaws.com with an aws:SourceAccount condition. See the guide for the full base and per-connector permissions.

6. Write the payment policy

python3 scripts/agents_pay_admin.py init-config \
  --max-per-payment-usd 0.05 \
  --network eip155:84532 \
  --recipient 0xMerchantWalletAddress

To find a merchant's real payTo and amount before allowlisting, read its challenge without paying:

curl -sD - https://<merchant-host>/<path> -o /dev/null \
  | awk '/^payment-required:/{print $2}' | base64 -d | python3 -m json.tool

Inspect accepts[].payTo, .amount (integer base units; USDC has 6 decimals, so 2000 = $0.002), .asset, and .network, then allowlist deliberately with --recipient. Unknown recipients are refused before signing.

If the operator deliberately accepts publisher-selected beneficiaries, replace all --recipient flags with --allow-any-recipient. These modes are mutually exclusive. The flag does not relax scheme, network, asset, origin/resource, per-payment, or cumulative session limits.

Add --origin https://host (repeatable) only if you want to pin the agent to a known merchant set; omitted, it may fetch any public HTTPS site.

7. Create the per-user instrument

One wallet for this installation. The payer identity is read from the config, where init-config generated it — this skill is single-tenant, so there is nothing to invent or keep in sync:

python3 scripts/agents_pay_admin.py create-instrument --email you@example.com

The manager ARN and connector ID are read from agentcore/.cli/deployed-state.json automatically, so run this from your AgentCore project directory. Otherwise pass --manager-arn and --connector-id explicitly.

Add --network-family SOLANA for Solana; the default ETHEREUM covers Base and Base Sepolia.

Run it under the setup role, not the runtime role. It prints the instrument ID, the wallet address, the delegation URL, and the export lines for the runtime.

8. Delegation and funding

One-time per wallet, and do this before creating a session.

Both steps attach to the wallet, not to a session: create_payment_session takes only a user, an expiry, and a budget. Sessions are time-bounded (60 minutes by default), so minting one first and then going off to complete a browser flow and a faucet transfer simply burns the clock — the budget can expire before the agent has spent anything.

Delegation — authorize the agent to spend from the wallet:

  • Coinbase CDP: the end user visits the redirectUrl, signs in, grants permission to the wallet address
  • Stripe Privy: no redirect URL; use the Privy frontend SDK (https://github.com/privy-io/aws-agentcore-sdk), sign in with the end user's email, approve delegation

Funding — send testnet USDC to the wallet address via https://faucet.circle.com/ (Base Sepolia). Fund only what the agent may plausibly spend: wallet balance is the backstop if every other control fails.

9. Approve a session and run preflight

python3 scripts/agents_pay_admin.py new-session --budget 1.00 --expiry-minutes 60

export PAYMENT_MANAGER_ARN=...   PAYMENT_INSTRUMENT_ID=...
export PAYMENT_SESSION_ID=...    PAYMENT_USER_ID=alice
export AWS_REGION=us-west-2

python3 scripts/agents_pay_admin.py preflight
python3 scripts/test_x402_policy.py

Keep sessions short (≤60 minutes) and budgets small. When the budget is spent, a human runs new-session again — the agent cannot.

Networks

Two distinct concepts, and mixing them up is a common setup failure:

  • network family — used when creating the instrument (--network-family)
  • chain — the CAIP-2 identifier that appears in x402 challenges and in this skill's allowed_networks

Families (instrument creation):

Family Value Covers Providers
Ethereum ETHEREUM Base, Base Sepolia, Ethereum mainnet Coinbase, Stripe
Solana SOLANA Solana, Solana Devnet Coinbase, Stripe

Chains (x402 challenges, allowed_networks, balance queries):

Chain CAIP-2 identifier Balance API value Type Providers
Base Sepolia eip155:84532 (or base-sepolia) BASE_SEPOLIA Testnet Coinbase
Base eip155:8453 BASE Mainnet Coinbase
Ethereum eip155:1 ETHEREUM Mainnet Coinbase, Stripe
Solana solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp SOLANA Mainnet Coinbase, Stripe
Solana Devnet solana-devnet SOLANA_DEVNET Testnet Stripe

Start on Base Sepolia (family ETHEREUM, chain eip155:84532) — free testnet USDC from https://faucet.circle.com/. init-config only knows the USDC contract for the Base chains; adding another chain means adding its exact contract to KNOWN_USDC in the admin CLI, deliberately, rather than passing an address in.

Operational monitoring

  • Confirm CloudTrail records bedrock-agentcore calls, especially ProcessPayment
  • Alarm on CreatePaymentSession by the runtime principal — it should be impossible, so any occurrence means the IAM split has regressed
  • Alarm on repeated ProcessPayment failures as an abuse signal
  • Review show-config output whenever payments start refusing unexpectedly

Source: SKILL.md on GitHub

1 alert1mo3 checks · Risk SAFE
  • Gen Agent Trust Hub1mo

    This skill provides a secure framework for AI agents to settle x402-protected payment challenges using AWS AgentCore. It includes robust security measures such as SSRF protection, strict IAM role separation, and content isolation to prevent prompt injection from paid external resources.

  • Socket1mo

    No alerts

  • Snyk1mo

    Risk: CRITICAL · 3 issues

Signed by skilld at 9766f27. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub yesterday.

Activeupdated 2 months ago
metadata
{
  "type": "skill",
  "version": "1.0.0",
  "author": "aws-agentcore"
}
All 1 allowed tools
Read Bash

README badge

README badge for aws/agent-toolkit-for-aws/agents-pay