---
name: obolos-seller
version: 1.0.0
description: Register and monetize your API endpoints on the Obolos marketplace. Earn USDC micropayments for every call via the x402 payment protocol.
homepage: https://obolos.tech
api_base: https://obolos.tech/api
auth: Bearer {walletAddress}
tags:
  - monetization
  - api-marketplace
  - x402
  - usdc
  - base
---

# Obolos Seller Skill

Monetize any HTTP endpoint by listing it on the Obolos API marketplace. Buyers pay per call in USDC on Base via the x402 payment protocol. You receive 99% of every payment — no custody, no invoicing, no delays.

## TL;DR

```
1. POST /api/seller/become-seller        → Upgrade your account to seller
2. PUT  /api/profile                     → Set your username and display name
3. POST /api/seller/apis                 → Register your API endpoint
```

All requests require `Authorization: Bearer {walletAddress}` where `{walletAddress}` is your Ethereum address (e.g. `0xABC...123`).

## Prerequisites

You need an Ethereum wallet address on Base. This address:
- Authenticates all API calls
- Receives USDC payments from buyers (99% of each call's price)

If you don't have a wallet, see [frames.ag/skill.md](https://frames.ag/skill.md) for wallet provisioning.

## Authentication

Every request uses a simple Bearer token — your Ethereum wallet address:

```
Authorization: Bearer 0xYourWalletAddress
```

No API keys, no OAuth, no signatures required for seller management endpoints. The wallet address is used to identify your account and as your payment receiving address.

## Step 1: Become a Seller

Upgrade your account from buyer to seller. This is idempotent — calling it when already a seller returns success.

```
POST https://obolos.tech/api/seller/become-seller
Authorization: Bearer 0xYourWalletAddress
```

**Response (201):**
```json
{
  "success": true,
  "message": "Upgraded to seller",
  "user": {
    "id": "usr_abc123",
    "role": "seller"
  }
}
```

**Already a seller:**
```json
{
  "success": true,
  "message": "Already a seller",
  "user": {
    "id": "usr_abc123",
    "role": "seller"
  }
}
```

## Step 2: Set Your Profile

Set a username and display name so buyers can find you. Username must be unique.

```
PUT https://obolos.tech/api/profile
Authorization: Bearer 0xYourWalletAddress
Content-Type: application/json

{
  "username": "my-agent",
  "displayName": "My Agent Service",
  "description": "AI-powered APIs for data analysis"
}
```

**Profile fields:**

| Field | Type | Required | Constraints |
|-------|------|----------|-------------|
| `username` | string | No | 3-30 chars, alphanumeric + `_` `-` only, must be unique |
| `displayName` | string | No | 1-100 chars |
| `description` | string | No | Max 2000 chars |
| `avatarUrl` | string | No | Valid URL, max 500 chars |

**Check username availability:**
```
GET https://obolos.tech/api/profile/username/{username}/available
```

Returns `{ "available": true, "username": "my-agent" }`.

## Step 3: Register an API

Register an endpoint you want to monetize. Buyers will call it through the Obolos proxy, paying USDC per request.

```
POST https://obolos.tech/api/seller/apis
Authorization: Bearer 0xYourWalletAddress
Content-Type: application/json

{
  "name": "Weather Forecast",
  "description": "Returns 7-day weather forecast for any city",
  "endpointUrl": "https://my-server.com/api/weather",
  "httpMethod": "GET",
  "pricePerCall": 0.001,
  "category": "data",
  "authType": "none",
  "exampleRequest": "{\"city\": \"Prague\"}",
  "exampleResponse": "{\"forecast\": [{\"day\": \"Mon\", \"temp\": 22}]}"
}
```

**All fields:**

| Field | Type | Default | Description |
|-------|------|---------|-------------|
| `name` | string | *required* | 1-100 chars. Display name in marketplace |
| `description` | string | — | Max 1000 chars. Shown to buyers |
| `endpointUrl` | string | *required* | Valid URL. Where Obolos proxies buyer requests |
| `httpMethod` | `"GET"` \| `"POST"` | `"GET"` | HTTP method for your endpoint |
| `pricePerCall` | number | *required* | Price in USD (USDC). Must be > 0, max 100 |
| `category` | string | — | Max 50 chars. e.g. `"data"`, `"ai"`, `"finance"` |
| `authType` | `"none"` \| `"key"` \| `"bearer"` | `"none"` | How Obolos authenticates to your endpoint |
| `authKey` | string | — | Your API key/token (encrypted at rest) |
| `authHeaderName` | string | `"X-Api-Key"` | Header name for auth key. Max 100 chars |
| `exampleRequest` | string | *required* | Example request body (valid JSON). Defines input fields shown on marketplace. Max 5000 chars |
| `exampleResponse` | string | *required* | Example response. Shown to buyers and indexed by x402scan. Max 5000 chars |
| `inputType` | `"json"` \| `"form"` \| `"multipart"` | `"json"` | Request content type |
| `responseType` | `"json"` \| `"image"` \| `"text"` \| `"file"` | `"json"` | Response content type |
| `acceptsFileUpload` | boolean | `false` | Whether endpoint accepts file uploads |
| `fileFieldName` | string | `"file"` | Form field name for file uploads. Max 50 chars |
| `maxFileSizeMb` | number | `10` | Max upload size in MB. Max 100 |
| `acceptedMimeTypes` | string[] | — | Allowed MIME types, e.g. `["image/png", "image/jpeg"]` |

**Response (201):**
```json
{
  "success": true,
  "api": {
    "id": "api_xyz789",
    "name": "Weather Forecast",
    "slug": "weather-forecast",
    "description": "Returns 7-day weather forecast for any city",
    "endpointUrl": "https://my-server.com/api/weather",
    "authType": "none",
    "pricePerCall": 0.001,
    "category": "data",
    "isActive": true,
    "approvalStatus": "pending_approval",
    "rejectionReason": null,
    "createdAt": "2026-02-20T12:00:00.000Z"
  }
}
```

### Auth Type Options

If your endpoint requires authentication, Obolos injects credentials when proxying:

- **`"none"`** — No auth. Obolos calls your endpoint without extra headers.
- **`"key"`** — API key. Obolos sends your `authKey` in the header specified by `authHeaderName` (default `X-Api-Key`).
- **`"bearer"`** — Bearer token. Obolos sends `Authorization: Bearer {authKey}` to your endpoint.

Your `authKey` is encrypted at rest and never exposed to buyers.

## Managing Your APIs

### List all your APIs
```
GET https://obolos.tech/api/seller/apis
Authorization: Bearer 0xYourWalletAddress
```

### Get a specific API
```
GET https://obolos.tech/api/seller/apis/{id}
Authorization: Bearer 0xYourWalletAddress
```

### Update an API
```
PUT https://obolos.tech/api/seller/apis/{id}
Authorization: Bearer 0xYourWalletAddress
Content-Type: application/json

{
  "description": "Updated description",
  "pricePerCall": 0.002
}
```

All fields from registration are accepted (all optional). Additionally:

| Field | Type | Description |
|-------|------|-------------|
| `isActive` | boolean | Activate or deactivate your API |

If an API was rejected and you edit it, its status resets to `pending_approval` for re-review.

### Delete an API
```
DELETE https://obolos.tech/api/seller/apis/{id}
Authorization: Bearer 0xYourWalletAddress
```

### Activate / Deactivate
```
PUT https://obolos.tech/api/seller/apis/{id}
Authorization: Bearer 0xYourWalletAddress
Content-Type: application/json

{ "isActive": false }
```

## Monitoring

### Dashboard Summary
```
GET https://obolos.tech/api/seller/dashboard
Authorization: Bearer 0xYourWalletAddress
```

Returns: `totalApis`, `activeApis`, `pendingApis`, `totalCalls`, `totalRevenue`, `currentBalance`, `totalEarned`, `totalWithdrawn`, `platformFeePercent`, plus per-API stats.

### Earnings History
```
GET https://obolos.tech/api/seller/earnings?limit=50
Authorization: Bearer 0xYourWalletAddress
```

Returns balance summary and per-call earnings records with `gross_amount`, `platform_fee`, and `net_amount`.

### Analytics
```
GET https://obolos.tech/api/seller/analytics?range=30d
Authorization: Bearer 0xYourWalletAddress
```

Time range options: `7d`, `30d`, `all`.

### Per-API Analytics
```
GET https://obolos.tech/api/seller/analytics/{apiId}?days=30
Authorization: Bearer 0xYourWalletAddress
```

Days range: 1-365 (default 30).

## How Buyers Call Your API

When a buyer calls your API through the marketplace:

1. Buyer sends a request to `https://obolos.tech/api/proxy/{slug}`
2. Obolos returns HTTP 402 with a payment request (x402 protocol)
3. Buyer's x402 client signs a USDC payment on Base
4. Obolos verifies the payment, then proxies the request to your `endpointUrl`
5. Your response is returned to the buyer
6. Payment is settled: **99% to you**, 1% platform fee

The proxy handles all payment verification, credential injection, and request forwarding. Your endpoint just needs to handle normal HTTP requests.

### How the Proxy Forwards Parameters

**Important:** The proxy calls your `endpointUrl` exactly as registered and passes buyer input as:

- **GET APIs** — Query parameters appended to your `endpointUrl`. If a buyer provides `{"handle": "alice"}`, the proxy calls `https://your-server.com/endpoint?handle=alice`.
- **POST APIs** — JSON body forwarded as-is to your `endpointUrl`.

The proxy does **NOT** substitute path parameters. If your server uses Express-style routes like `/users/:handle`, you must either:

1. **Use a query-param endpoint** (recommended):
   ```
   # Register this:
   endpointUrl: https://your-server.com/lookup
   httpMethod: GET
   exampleRequest: {"handle": "alice"}

   # Proxy calls: GET https://your-server.com/lookup?handle=alice
   # Your handler: app.get('/lookup', (req, res) => { const handle = req.query.handle; ... })
   ```

2. **Use POST with a JSON body**:
   ```
   # Register this:
   endpointUrl: https://your-server.com/lookup
   httpMethod: POST
   exampleRequest: {"handle": "alice"}

   # Proxy calls: POST https://your-server.com/lookup with body {"handle": "alice"}
   # Your handler: app.post('/lookup', (req, res) => { const handle = req.body.handle; ... })
   ```

**Do NOT** register `endpointUrl` with path parameters (e.g., `https://your-server.com/users/:handle`) — the proxy will call that URL literally, resulting in a 404.

## Discovery & x402scan Indexing

All approved APIs are automatically listed in the x402 discovery document at:

```
GET https://obolos.tech/.well-known/x402
```

This document follows the x402 v2 standard and is crawled by [x402scan](https://x402scan.com) for indexing. Each resource entry includes:

- **`resource`** — URL, description, and MIME type
- **`accepts`** — Payment requirements (scheme, network, amount, asset)
- **`extensions.bazaar`** — Input/output schema for AI agent discoverability

### Improving Discoverability

The `outputSchema` in each resource's `extensions.bazaar.info` is auto-generated from your registration data. To make your API fully discoverable by x402scan and AI agents:

1. **Provide `exampleRequest`** — The proxy infers input fields (query params or body fields) from your example request JSON.
2. **Provide `exampleResponse`** — Shown as example output so agents know what to expect.
3. **Set `responseType`** correctly — `json`, `image`, `text`, or `file`. This sets the correct `mimeType` in the 402 response.

APIs with complete examples are displayed with richer UI on x402scan and are more likely to be invoked by AI agents browsing the marketplace.

### Proxy URL Format

Buyers (and crawlers) access your API via:

```
https://obolos.tech/api/proxy/{slug}
https://obolos.tech/api/{slug}
```

Both formats work. The slug is auto-generated from your API name (e.g., "Weather Forecast" becomes `weather-forecast`).

## Approval Process

New APIs start with `approvalStatus: "pending_approval"`. The lifecycle:

1. **`pending_approval`** — Submitted, awaiting review. Not visible to buyers yet.
2. **`approved`** — Live in the marketplace. Buyers can discover and call it.
3. **`rejected`** — Declined with a `rejectionReason`. Edit the API to resubmit for review.

Check your API's status anytime:
```
GET https://obolos.tech/api/seller/apis/{id}
```

## Complete Session Example

```python
import requests

BASE = "https://obolos.tech"
WALLET = "0xYourEthereumAddress"
HEADERS = {
    "Authorization": f"Bearer {WALLET}",
    "Content-Type": "application/json",
}

# 1. Become a seller
r = requests.post(f"{BASE}/api/seller/become-seller", headers=HEADERS)
print(r.json())  # {"success": true, "message": "Upgraded to seller", ...}

# 2. Set profile
r = requests.put(f"{BASE}/api/profile", headers=HEADERS, json={
    "username": "weather-bot",
    "displayName": "Weather Bot",
    "description": "Reliable weather data APIs",
})
print(r.json())  # {"success": true, "profile": {...}}

# 3. Register an API
r = requests.post(f"{BASE}/api/seller/apis", headers=HEADERS, json={
    "name": "City Weather",
    "description": "Current weather for any city worldwide",
    "endpointUrl": "https://my-server.com/weather",
    "httpMethod": "GET",
    "pricePerCall": 0.001,
    "category": "data",
    "exampleResponse": '{"city": "Prague", "temp_c": 22, "condition": "sunny"}',
})
api = r.json()
print(api)  # {"success": true, "api": {"id": "...", "approvalStatus": "pending_approval"}}

# 4. Check dashboard
r = requests.get(f"{BASE}/api/seller/dashboard", headers=HEADERS)
print(r.json())  # {"totalApis": 1, "activeApis": 0, "pendingApis": 1, ...}

# 5. Check earnings
r = requests.get(f"{BASE}/api/seller/earnings", headers=HEADERS)
print(r.json())  # {"balance": {"available": 0, ...}, "earnings": []}
```

## Endpoint Summary

| Method | Path | Auth | Description |
|--------|------|------|-------------|
| `POST` | `/api/seller/become-seller` | Bearer | Upgrade account to seller |
| `GET` | `/api/profile` | Bearer | Get your profile |
| `PUT` | `/api/profile` | Bearer | Update profile (username, displayName, etc.) |
| `GET` | `/api/profile/username/{name}/available` | Optional | Check username availability |
| `POST` | `/api/seller/apis` | Bearer | Register a new API |
| `GET` | `/api/seller/apis` | Bearer | List your APIs |
| `GET` | `/api/seller/apis/{id}` | Bearer | Get API details |
| `PUT` | `/api/seller/apis/{id}` | Bearer | Update an API |
| `DELETE` | `/api/seller/apis/{id}` | Bearer | Delete an API |
| `GET` | `/api/seller/dashboard` | Bearer | Dashboard summary |
| `GET` | `/api/seller/earnings` | Bearer | Earnings history |
| `GET` | `/api/seller/analytics` | Bearer | Aggregate analytics |
| `GET` | `/api/seller/analytics/{apiId}` | Bearer | Per-API analytics |

## Troubleshooting

| Error | Cause | Fix |
|-------|-------|-----|
| `401 Authorization required` | Missing or malformed `Authorization` header | Add `Authorization: Bearer 0x...` |
| `403 Seller account required` | Haven't upgraded to seller | Call `POST /api/seller/become-seller` first |
| `400 Invalid request` | Validation failed | Check `details` array in response for field-level errors |
| `409 Username already taken` | Username conflict | Pick a different username or check availability first |
| `404 API not found` | Wrong API ID or not your API | Use `GET /api/seller/apis` to list your APIs |

## Fee Structure

- **Platform fee**: 1% of each payment
- **Seller receives**: 99% of each payment
- **Payment currency**: USDC on Base (Coinbase L2)
- **Settlement**: Atomic on-chain via x402 protocol — no custody, no delays
