Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions python/coinbase-agentkit/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -536,6 +536,24 @@ This section provides a detailed list of all available action providers and thei
</table>
</details>

<details>
<summary><strong>x402</strong></summary>
<table width="100%">
<tr>
<td width="200"><code>make_http_request</code></td>
<td width="768">Makes a basic HTTP request to an API endpoint. If the endpoint requires payment (returns 402), it will return payment details that can be used with retry_http_request_with_x402.</td>
</tr>
<tr>
<td width="200"><code>retry_http_request_with_x402</code></td>
<td width="768">Retries an HTTP request with x402 payment after receiving a 402 Payment Required response. This should be used after make_http_request returns a 402 response.</td>
</tr>
<tr>
<td width="200"><code>make_http_request_with_x402</code></td>
<td width="768">Makes an HTTP request with automatic x402 payment handling. Only use when explicitly told to skip the confirmation flow.</td>
</tr>
</table>
</details>

## Wallet Providers

AgentKit supports the following wallet providers:
Expand Down
1 change: 1 addition & 0 deletions python/coinbase-agentkit/changelog.d/778.feature.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Added x402ActionProvider
2 changes: 2 additions & 0 deletions python/coinbase-agentkit/coinbase_agentkit/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
wallet_action_provider,
weth_action_provider,
wow_action_provider,
x402_action_provider,
)
from .agentkit import AgentKit, AgentKitConfig
from .wallet_providers import (
Expand Down Expand Up @@ -64,5 +65,6 @@
"wallet_action_provider",
"weth_action_provider",
"wow_action_provider",
"x402_action_provider",
"__version__",
]
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
from .wallet.wallet_action_provider import WalletActionProvider, wallet_action_provider
from .weth.weth_action_provider import WethActionProvider, weth_action_provider
from .wow.wow_action_provider import WowActionProvider, wow_action_provider
from .x402.x402_action_provider import x402_action_provider, x402ActionProvider

__all__ = [
"Action",
Expand Down Expand Up @@ -64,4 +65,6 @@
"weth_action_provider",
"WowActionProvider",
"wow_action_provider",
"x402ActionProvider",
"x402_action_provider",
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
# X402 Action Provider

This directory contains the **X402ActionProvider** implementation, which provides actions to interact with **x402-protected APIs** that require payment to access.

## Directory Structure

```
x402/
├── x402_action_provider.py # Main provider with x402 payment functionality
├── schemas.py # x402 action schemas
├── __init__.py # Main exports
└── README.md # This file
```

## Actions

### Primary Actions (Recommended Flow)

1. `make_http_request`: Make initial HTTP request and handle 402 responses
2. `retry_http_request_with_x402`: Retry a request with payment after receiving payment details

### Alternative Action

- `make_http_request_with_x402`: Direct payment-enabled requests (skips confirmation flow)

## Overview

The x402 protocol enables APIs to require micropayments for access. When a client makes a request to a protected endpoint, the server responds with a `402 Payment Required` status code along with payment instructions.

### Recommended Two-Step Flow

1. Initial Request:
- Make request using `make_http_request`
- If endpoint doesn't require payment, get response immediately
- If 402 received, get payment options and instructions

2. Payment & Retry (if needed):
- Review payment requirements
- Use `retry_http_request_with_x402` with chosen payment option
- Get response with payment proof

This flow provides better control and visibility into the payment process.

### Direct Payment Flow (Alternative)

For cases where immediate payment without confirmation is acceptable, use `make_http_request_with_x402` to handle everything in one step.

## Usage

### `make_http_request` Action

Makes initial request and handles 402 responses:

```python
{
"url": "https://api.example.com/data",
"method": "GET", # Optional, defaults to GET
"headers": { "Accept": "..." }, # Optional
"body": { ... } # Optional
}
```

Response format for 402 status:
```python
{
"status": "error_402_payment_required",
"acceptablePaymentOptions": [
{
"scheme": "exact",
"network": "base-sepolia",
"maxAmountRequired": "1000",
"resource": "https://api.example.com/data",
"description": "Access to data",
"mimeType": "application/json",
"payTo": "0x...",
"maxTimeoutSeconds": 300,
"asset": "0x..."
}
],
"nextSteps": [
"Inform the user that the server replied with a 402 Payment Required response.",
"The payment options are: [asset] [amount] [network]",
"Ask the user if they want to retry the request with payment.",
"Use retry_http_request_with_x402 to retry the request with payment."
]
}
```

### `retry_http_request_with_x402` Action

Retries request with payment after 402:

```python
{
"url": "https://api.example.com/data",
"method": "GET", # Optional, defaults to GET
"headers": { "Accept": "..." }, # Optional
"body": { ... }, # Optional
# Payment details (all fields required)
"scheme": "exact",
"network": "base-sepolia",
"max_amount_required": "1000",
"resource": "https://api.example.com/data",
"pay_to": "0x...",
"max_timeout_seconds": 300,
"asset": "0x...",
# Optional payment details
"description": "", # Optional
"mime_type": "", # Optional
"output_schema": null, # Optional
"extra": null # Optional
}
```

### `make_http_request_with_x402` Action

Direct payment-enabled requests (use with caution):

```python
{
"url": "https://api.example.com/data",
"method": "GET", # Optional, defaults to GET
"headers": { "Accept": "..." }, # Optional
"body": { ... } # Optional
}
```

## Response Format

Successful responses include payment proof when payment was made:

```python
{
"status": "success",
"data": { ... }, # API response data
"message": "Request completed successfully with payment",
"details": {
"url": "https://api.example.com/data",
"method": "GET",
"paymentUsed": {
"network": "base-sepolia",
"asset": "0x...",
"amount": "1000"
},
"paymentProof": { # Only present if payment was made
"transaction": "0x...", # Transaction hash
"network": "base-sepolia",
"payer": "0x..." # Payer address
}
}
}
```

Error responses include helpful details and suggestions:
```python
{
"error": true,
"message": "Error description",
"details": "Detailed error information",
"suggestion": "Helpful suggestion for resolving the error"
}
```

## Network Support

The x402 provider currently supports the following networks:
- `base-mainnet`
- `base-sepolia`

The provider requires EVM-compatible networks where the wallet can sign payment transactions.

## Dependencies

This action provider requires:
- `requests` - For making HTTP requests
- `x402` - For payment requirement types and validation
- An EVM-compatible wallet provider for signing transactions

## Notes

For more information on the **x402 protocol**, visit the [x402 documentation](https://x402.gitbook.io/x402/).
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
"""CDP EVM Server action provider for CDP protocol interactions."""

from .x402_action_provider import x402_action_provider

__all__ = ["x402_action_provider"]
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
"""Schemas for x402 action providers."""

from typing import Any, Literal

from pydantic import BaseModel, Field


class HttpRequestSchema(BaseModel):
"""Schema for making basic HTTP requests."""

url: str = Field(
..., description="The URL of the API endpoint (can be localhost for development)"
)
method: Literal["GET", "POST", "PUT", "DELETE", "PATCH"] = Field(
default="GET", description="The HTTP method to use for the request"
)
headers: dict[str, str] | None = Field(
default=None, description="Optional headers to include in the request"
)
body: Any | None = Field(
default=None, description="Optional request body for POST/PUT/PATCH requests"
)

class Config:
"""Pydantic config."""

title = "Instructions for making a basic HTTP request"


class RetryWithX402Schema(BaseModel):
"""Schema for retrying requests with x402 payment."""

url: str = Field(
..., description="The URL of the API endpoint (can be localhost for development)"
)
method: Literal["GET", "POST", "PUT", "DELETE", "PATCH"] = Field(
default="GET", description="The HTTP method to use for the request"
)
headers: dict[str, str] | None = Field(
default=None, description="Optional headers to include in the request"
)
body: Any | None = Field(
default=None, description="Optional request body for POST/PUT/PATCH requests"
)
scheme: str = Field(..., description="The payment scheme to use")
network: str = Field(..., description="The network to use for payment")
max_amount_required: str = Field(..., description="The maximum amount required for payment")
resource: str = Field(..., description="The resource URL that requires payment")
description: str = Field(default="", description="Description of the payment requirement")
mime_type: str = Field(default="", description="MIME type of the response")
output_schema: dict[str, Any] | None = Field(
default=None, description="Schema of the expected output"
)
pay_to: str = Field(..., description="Address to send payment to")
max_timeout_seconds: int = Field(..., description="Maximum timeout in seconds")
asset: str = Field(..., description="Asset contract address to use for payment")
extra: dict[str, Any] | None = Field(default=None, description="Additional payment metadata")

class Config:
"""Pydantic config."""

title = (
"Instructions for retrying a request with x402 payment after receiving a 402 response"
)


class DirectX402RequestSchema(BaseModel):
"""Schema for direct x402 payment requests."""

url: str = Field(
..., description="The URL of the API endpoint (can be localhost for development)"
)
method: Literal["GET", "POST", "PUT", "DELETE", "PATCH"] = Field(
default="GET", description="The HTTP method to use for the request"
)
headers: dict[str, str] | None = Field(
default=None, description="Optional headers to include in the request"
)
body: Any | None = Field(
default=None, description="Optional request body for POST/PUT/PATCH requests"
)

class Config:
"""Pydantic config."""

title = "Instructions for making an HTTP request with automatic x402 payment handling. WARNING: This bypasses user confirmation - only use when explicitly told to skip confirmation!"
Loading