Status: Draft Created: 2026-03-15 Updated: 2026-03-19 Authors: 402md contributors Reference Implementation: @402md/skillmd
SKILL.md is an open format for describing capabilities that AI agents can discover, understand, and use — including paid APIs, free tools, and agent instructions. A single markdown file, readable by both humans and machines, serves as the universal descriptor for the agent economy.
SKILL.md is designed as a superset of existing skill formats (including Anthropic Claude Code skills) and extends them with payment, endpoint, and discovery metadata. Any valid Anthropic skill is a valid SKILL.md. Any valid SKILL.md is usable by agents that understand the format.
- Human-readable — A SKILL.md is a markdown file. Developers read it, edit it, commit it.
- Machine-parseable — YAML frontmatter provides structured metadata for agents and tools.
- Framework-agnostic — Works with MCP, A2A, OpenAPI, LangChain, or any agent framework.
- Payment-native — First-class support for pricing, payment networks, and non-custodial settlement.
- Backwards-compatible — Anthropic Claude Code skills (name + description) parse as valid SKILL.md.
- Extensible — Unknown frontmatter fields are preserved, not rejected.
A SKILL.md file consists of two parts separated by --- delimiters:
---
[YAML frontmatter]
---
[Markdown body]
- Frontmatter — YAML between the opening and closing
---. Contains structured metadata. - Body — Markdown content after the closing
---. Contains documentation, instructions, or both. - Encoding — UTF-8. Both LF and CRLF line endings are accepted.
- File name — MUST be
SKILL.md(case-sensitive).
The frontmatter is extracted using the following pattern:
^---\r?\n([\s\S]*?)\r?\n---\r?\n?([\s\S]*)$
The first capture group is the YAML content. The second is the markdown body.
These fields are shared with the Anthropic Claude Code skill format and provide base compatibility.
| Field | Type | Required | Description |
|---|---|---|---|
name |
string |
Yes | Unique identifier. Kebab-case (^[a-z0-9][a-z0-9_-]*$). Max 100 chars. |
description |
string |
Yes | What this skill does. Max 2000 chars. For agent-invoked skills, use trigger phrases (see §3.1.1). |
version |
string |
No | Semantic version (MAJOR.MINOR.PATCH). |
The description field serves two purposes:
- Human discovery — Tells developers what the skill does.
- Agent triggering — Tells AI agents when to invoke the skill.
For skills intended to be auto-invoked by agents (e.g., Claude Code skills), use the Anthropic trigger phrase pattern:
description: >-
This skill should be used when the user asks to "scrape a website",
"extract web data", "crawl pages", or needs web content extraction.
Real-time web scraping API with structured output.For pure API descriptors, a plain description is sufficient:
description: Real-time web scraping API with structured outputBoth styles are valid. Parsers MUST accept both.
| Field | Type | Required | Description |
|---|---|---|---|
displayName |
string |
No | Human-readable name (max 200 chars). Falls back to name. |
author |
string |
No | Author or organization name (max 100 chars). |
license |
string |
No | License identifier (e.g., MIT, proprietary). |
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
type |
SkillType |
No | API |
Category of the skill. |
pricingModel |
PricingModel |
No | — | Payment semantics for the skill. |
tags |
string[] |
No | [] |
Discovery tags (max 20 items). |
category |
string |
No | — | Primary category for marketplace listing. |
SkillType enum:
| Value | Description | Typical pricingModel |
|---|---|---|
API |
RESTful API with per-call pricing | fixed |
SAAS |
Software-as-a-Service with API access | subscription |
PRODUCT |
Digital or physical product | cart or dynamic |
SERVICE |
Human-in-the-loop or async service | dynamic |
SUBSCRIPTION |
Recurring time-based access | subscription |
CONTENT |
Static content (docs, reports, etc.) | fixed |
SKILL |
Agent instruction/prompt (no paid endpoints) | free |
Note: The
SKILLtype indicates a pure agent instruction (Anthropic-style skill) with no paid endpoints. Thepaymentandendpointsfields are optional whentype: SKILL.
PricingModel enum:
| Value | Description | x402 behavior |
|---|---|---|
fixed |
Every endpoint has a known, fixed price per call | Standard x402 flow |
dynamic |
Price varies per request (server calculates at request time) | 402 response contains the real amount |
subscription |
Pay once for time-based access, then use endpoints freely | x402 for subscription payment; wallet signature for subsequent auth |
cart |
Agent collects items, server calculates total at checkout | Free endpoints for browsing; x402 with dynamic price at checkout |
free |
No payment required for any endpoint | No x402 middleware |
The pricingModel field describes the overall payment semantics of the skill. Individual endpoints may still have different prices (priceUsdc: "0" for free, "dynamic" for variable, or a fixed decimal).
| Field | Type | Required | Description |
|---|---|---|---|
base_url |
string (URL) |
Conditional | Base URL of the API. Required when endpoints is present. |
sla |
string |
No | Uptime guarantee (e.g., "99.9%"). |
rateLimit |
string |
No | Rate limit (e.g., "1000/hour"). |
sandbox |
string (URL) |
No | Free test endpoint URL. |
The payment block describes how agents pay for the skill. It is required when endpoints is present, and optional when type: SKILL.
payment:
asset: USDC
networks:
- network: stellar
payTo: GABC...XYZ
facilitator: https://facilitator.402.md
- network: base
payTo: 0xabc...def
facilitator: https://facilitator-base.402.mdEach entry in the networks array co-locates the network identifier with its recipient address and facilitator, eliminating ambiguity when supporting multiple chains.
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
payment.asset |
string |
No | USDC |
Payment asset/token. |
payment.networks |
NetworkConfig[] |
Yes | — | Supported payment networks with per-network configuration (min 1). |
payment.networks[].network |
PaymentNetwork |
Yes | — | Network identifier. |
payment.networks[].payTo |
string |
Yes | — | Recipient address for this network (Stellar G-address or EVM 0x-address). |
payment.networks[].facilitator |
string (URL) |
No | — | Facilitator service URL for this network. |
PaymentNetwork enum:
| Value | Description |
|---|---|
stellar |
Stellar mainnet |
stellar-testnet |
Stellar testnet |
base |
Base mainnet (Coinbase L2) |
base-sepolia |
Base Sepolia testnet |
The auth block describes how agents identify themselves for non-payment requests (e.g., after subscribing). It is optional and primarily used with pricingModel: subscription.
auth:
method: wallet-signature
loginEndpoint: /v1/auth| Field | Type | Required | Description |
|---|---|---|---|
auth.method |
string |
Yes (when auth present) |
Authentication method. Common value: wallet-signature. |
auth.loginEndpoint |
string |
No | Endpoint path for wallet-based authentication. Must start with /. |
How wallet-signature auth works:
In x402, the wallet address is the user's identity. After a subscription payment, the server knows the payer's address. For subsequent requests, the agent proves wallet ownership by signing a message — this is a free, local operation that does not involve the facilitator or blockchain.
1. Agent signs message: "Login: {timestamp}" with private key
2. Agent sends wallet + signature to loginEndpoint
3. Server verifies signature locally (free, ~1ms)
4. Server checks subscription status for that wallet
5. Server returns JWT for the subscription period
6. Agent uses JWT on subsequent requests
Important: Verifying a wallet signature is a local cryptographic operation. It does NOT go through the facilitator and costs nothing. The facilitator is only involved when actual payment (USDC transfer) occurs.
The endpoints array describes callable API endpoints with per-call pricing.
endpoints:
- path: /v1/scrape
method: POST
description: Scrape a URL and return structured content
priceUsdc: "0.005"
inputSchema:
type: object
properties:
url:
type: string
format: uri
required: [url]
outputSchema:
type: object
properties:
content:
type: string
title:
type: string| Field | Type | Required | Description |
|---|---|---|---|
endpoints[].path |
string |
Yes | Endpoint path. MUST start with /. |
endpoints[].method |
HttpMethod |
Yes | HTTP method. |
endpoints[].description |
string |
Yes | What this endpoint does. |
endpoints[].priceUsdc |
string |
Yes | Price per call in USDC (e.g., "0.001") or "dynamic" for server-determined pricing. Decimal format: `^(\d+(.\d+)? |
endpoints[].estimatedPriceUsdc |
string |
No | Estimated price for dynamic endpoints (e.g., "25.00"). Informational — the actual price comes from the 402 response. |
endpoints[].duration |
string |
No | Access duration granted by this endpoint (e.g., "30d", "1h", "1y"). Format: ^\d+(m|h|d|y)$. Used with subscription endpoints. |
endpoints[].deliveryMode |
DeliveryMode |
No | How results are delivered. Default: sync. |
endpoints[].inputSchema |
JSONSchema |
No | JSON Schema for the request body. |
endpoints[].outputSchema |
JSONSchema |
No | JSON Schema for the response body. |
HttpMethod enum: GET, POST, PUT, DELETE, PATCH.
DeliveryMode enum:
| Value | Description |
|---|---|
sync |
Response is immediate (default for API calls) |
polling |
Returns a job ID; agent polls a status endpoint for results |
webhook |
Server pushes results to a callback URL when ready |
When priceUsdc is "dynamic", the actual cost is determined by the server at request time and communicated via the HTTP 402 response. This is used for:
- Cart checkout — price = sum of items + shipping
- Variable-length processing — price depends on input size (e.g., word count for translation)
- Resource-based billing — price depends on compute time, storage, etc.
The estimatedPriceUsdc field provides budget guidance for agents. It SHOULD be set for dynamic endpoints so agents can inform users of approximate costs before making the call.
The x402 protocol already supports dynamic pricing natively — the server's paywall() middleware accepts any price, calculated per-request. The client.fetch() reads the amount from the 402 response and pays it (subject to budget limits).
# Fixed pricing — agent knows exact cost upfront
- path: /v1/search
priceUsdc: "0.001"
# Dynamic pricing — agent learns cost from 402 response
- path: /v1/checkout
priceUsdc: dynamic
estimatedPriceUsdc: "25.00"
# Free endpoint — no x402 paywall
- path: /v1/cart/view
priceUsdc: "0"Note: Endpoints with
priceUsdc: "0"do not require x402 payment middleware. They are regular HTTP endpoints.
These fields support integration with agent frameworks.
| Field | Type | Required | Description |
|---|---|---|---|
allowed-tools |
string | string[] |
No | Tools the skill is allowed to use (Anthropic compatibility). E.g., "Bash", ["Bash", "Read", "Write"]. |
The frontmatter schema allows additional properties (additionalProperties: true). Parsers MUST preserve unknown fields and MUST NOT reject them. This enables ecosystem-specific extensions without breaking compatibility.
Example extensions:
# MCP-specific
mcp_server: "@402md/mcp"
# Marketplace-specific
marketplace:
featured: true
verified: true
# Custom
x-internal-id: "12345"The body section after the frontmatter closing --- is the most important part of a SKILL.md. The frontmatter provides structured metadata for tooling, but the body is what an AI agent actually reads to understand how to use the skill.
Key insight: No LLM has been trained on x402. The body MUST teach the agent what x402 is, how payment works, and how to call each endpoint — step by step, with examples.
The body SHOULD follow this structure for paid APIs. Each section is designed so that an agent reading the SKILL.md top-to-bottom has everything it needs to operate autonomously.
# {Skill Name}
{One-paragraph description of what this skill does and when to use it.}
## Payment Protocol (x402)
{Explain the payment flow so the agent understands what happens when it
makes a request. This section is critical — without it, agents won't
know how to handle HTTP 402 responses.}
## Authentication
{Explain how the agent authenticates. For x402 skills, this is typically
"No API keys needed — pay per request via x402." For hybrid skills,
explain any additional auth requirements.}
## Endpoints
{For each endpoint: description, method, path, price, input/output
with concrete examples. Show full request/response payloads.}
### {Endpoint Name}
**{METHOD} {path}** — ${price} USDC
{Description of what this endpoint does.}
**Request:**
{Show the exact JSON body the agent should send.}
**Response:**
{Show the exact JSON the agent will receive.}
## Workflow
{Step-by-step guide for common use cases. Tell the agent exactly
what sequence of calls to make and in what order.}
## Error Handling
{What errors can occur and what the agent should do about each one.}
## Pricing Summary
{Quick reference table of all endpoints and their costs.}Every SKILL.md for a paid API MUST include instructions that teach the agent the x402 payment flow. Agents have not been trained on x402 — this is the only way they learn.
Recommended x402 section:
## Payment Protocol (x402)
This API uses the x402 payment protocol. No API keys or accounts needed.
Payment is per-request in USDC on {network}.
**How it works:**
1. Make a normal HTTP request to any endpoint
2. The server responds with HTTP 402 (Payment Required) and a JSON body
containing payment requirements (amount, recipient address, network)
3. Sign a USDC transfer authorization with your wallet (non-custodial,
no funds leave your wallet until verified)
4. Retry the same request with the signed payment in the `X-PAYMENT` header
5. The server verifies the payment, settles on-chain, and returns the result
**If using @402md/mcp:** Payment is handled automatically. Just call the
endpoint via `use_skill` and the MCP server handles steps 2-5.
**If calling directly:** Use `x402Fetch()` from `@402md/x402` which
auto-handles the 402 → sign → retry flow.Each endpoint SHOULD include complete request/response examples that an agent can copy directly. Abstract descriptions are insufficient — agents need concrete payloads.
Good (agent can execute immediately):
### Scrape a URL
**POST /v1/scrape** — $0.005 USDC
Extract structured content from any webpage.
**Request:**
\`\`\`json
{
"url": "https://example.com/article",
"format": "markdown",
"javascript": false
}
\`\`\`
**Response:**
\`\`\`json
{
"title": "Example Article",
"content": "# Article Title\n\nArticle body in markdown...",
"metadata": {
"author": "John Doe",
"publishedAt": "2026-03-15"
}
}
\`\`\`
**Parameters:**
- `url` (required): The URL to scrape. Must be a valid HTTP/HTTPS URL.
- `format`: Output format. `markdown` (default), `html`, or `text`.
- `javascript`: Set to `true` for SPAs/dynamic pages. Slower but renders JS.Bad (agent cannot execute):
### Scrape
Scrapes a URL and returns content.For skills with multiple endpoints, include a workflow section that tells the agent the exact sequence of operations for common tasks. Write in imperative form.
## Workflow
### Get current weather for a city
1. Call `POST /v1/current` with `{ "location": "New York" }` ($0.001)
2. If the user wants a forecast, call `POST /v1/forecast`
with `{ "location": "New York", "days": 7 }` ($0.005)
3. Always tell the user the cost before making the call
4. If the location is ambiguous, ask the user to clarify before calling
### Compare weather across cities
1. Call `POST /v1/current` once per city (each call costs $0.001)
2. Present results in a comparison table
3. Total cost = $0.001 × number of cities — confirm with user firstTell the agent what to do when things go wrong. Agents that don't know how to handle errors will either crash or hallucinate.
## Error Handling
| Status | Meaning | What to do |
|--------|---------|------------|
| 400 | Bad request | Check input format. Show the error message to the user. |
| 402 | Payment required | This is normal — the x402 flow handles it automatically. |
| 403 | Insufficient funds | Tell the user to fund their wallet. Show balance. |
| 404 | Not found | The resource doesn't exist. Don't retry. |
| 429 | Rate limited | Wait 60 seconds and retry once. If still 429, tell the user. |
| 500 | Server error | Retry once after 5 seconds. If still failing, tell the user. |For pure agent instructions (no paid endpoints), the body follows the Anthropic convention — imperative form, step-by-step procedures:
# Code Reviewer
When reviewing code, follow these steps:
1. Read the file completely before commenting
2. Check for security vulnerabilities (OWASP top 10)
3. Verify error handling at system boundaries
4. Suggest improvements only when asked| Skill complexity | Recommended body length |
|---|---|
| Simple (1-2 endpoints) | 500-1,000 words |
| Medium (3-5 endpoints) | 1,000-3,000 words |
| Complex (6+ endpoints, workflows) | 3,000-8,000 words |
| Platform API (many features) | 5,000-15,000 words |
Longer is better than shorter. An agent with too much context wastes tokens. An agent with too little context makes wrong API calls, wastes money, and fails. Err on the side of more detail.
A SKILL.md can serve different use cases. The required fields and payment semantics vary by profile:
For services that charge a fixed price per API call via x402.
Required: name, description, base_url, payment, endpoints
---
name: web-scraper
description: Real-time web scraping with structured output
base_url: https://api.scraper.dev
type: API
pricingModel: fixed
payment:
asset: USDC
networks:
- network: stellar
payTo: GABC...XYZ
endpoints:
- path: /v1/scrape
method: POST
description: Scrape a URL
priceUsdc: "0.005"
---See examples/api-weather/SKILL.md for a complete example.
For e-commerce where the agent acts as the shopping cart. The agent collects items and shipping info from the user, then sends everything in a single order request. The server calculates the total dynamically.
Required: name, description, base_url, payment, endpoints
---
name: acme-shop
type: PRODUCT
pricingModel: cart
endpoints:
- path: /v1/products/search
priceUsdc: "0" # free — browse without paying
- path: /v1/orders
priceUsdc: dynamic # price = cart total + shipping
estimatedPriceUsdc: "25.00"
---Key design principle: The cart lives in the agent's context, not on the server. The agent collects items during conversation and sends them all at checkout. This keeps the server stateless and reduces x402 payment round-trips to a single call.
See examples/shop-acme/SKILL.md for a complete example.
For services where the agent pays once for time-based access, then uses endpoints freely via wallet-based authentication.
Required: name, description, base_url, payment, endpoints, auth
---
name: analytics-pro
type: SUBSCRIPTION
pricingModel: subscription
auth:
method: wallet-signature
loginEndpoint: /v1/auth
endpoints:
- path: /v1/subscribe
priceUsdc: "10.00"
duration: "30d" # 30 days of access
- path: /v1/auth
priceUsdc: "0" # wallet auth is free
- path: /v1/data
priceUsdc: "0" # free after subscribing
---Identity model: The wallet address IS the user's identity. After paying via x402, the server knows the payer's address. For subsequent requests, the agent signs a message to prove wallet ownership — a free, local cryptographic operation that does not involve the facilitator.
See examples/saas-analytics/SKILL.md for a complete example.
For async services where results are not immediate (human review, heavy processing, etc.).
Required: name, description, base_url, payment, endpoints
---
name: human-translation
type: SERVICE
pricingModel: dynamic
endpoints:
- path: /v1/jobs
method: POST
priceUsdc: dynamic
estimatedPriceUsdc: "5.00"
deliveryMode: polling # agent polls for results
- path: /v1/jobs/{jobId}
method: GET
priceUsdc: "0" # status checks are free
deliveryMode: polling
---Delivery modes: When deliveryMode is polling, the agent should periodically check the status endpoint until the job completes. When webhook, the server pushes results to a callback URL.
See examples/service-translation/SKILL.md for a complete example.
For Claude Code skills and agent instructions. Compatible with Anthropic's format. No payment required.
Required: name, description
---
name: code-reviewer
description: >-
This skill should be used when the user asks to "review code",
"check for bugs", "audit this file", or mentions code quality.
version: 1.0.0
allowed-tools: [Read, Grep, Glob]
---
# Code Reviewer
When reviewing code, follow these steps:
1. Read the file completely before commenting
2. Check for security vulnerabilities (OWASP top 10)
3. Verify error handling at boundaries
4. Suggest improvements only when askedA paid API that also provides agent instructions for how to use it. Combines any paid profile (API, Product, Service) with agent workflow instructions in the body.
Required: name, description, base_url, payment, endpoints
---
name: weather-api
description: >-
This skill should be used when the user asks about "weather",
"temperature", "forecast", or needs meteorological data.
base_url: https://api.weatherco.com
type: API
pricingModel: fixed
allowed-tools: [Read, Bash]
payment:
asset: USDC
networks:
- network: stellar
payTo: GABC...XYZ
endpoints:
- path: /v1/current
method: POST
description: Get current weather
priceUsdc: "0.001"
tags: [weather, geolocation]
---
# Weather API
When the user asks about weather:
1. Call `/v1/current` with the location ($0.001 per call)
2. If they want a forecast, call `/v1/forecast` ($0.005)
3. Always show the cost before making the callA SKILL.md can be converted to and from multiple formats:
Each endpoint becomes an MCP tool:
| SKILL.md | MCP Tool |
|---|---|
name + endpoints[].path |
tool.name (e.g., weather-api_v1_current) |
endpoints[].description |
tool.description (appended with price info) |
endpoints[].inputSchema |
tool.inputSchema |
The SKILL.md maps to Google A2A Protocol Agent Card v0.3.0:
| SKILL.md | Agent Card |
|---|---|
name |
humanReadableId |
displayName || name |
name |
description |
description |
base_url |
url |
version |
agentVersion |
author |
provider.name |
endpoints[] |
skills[] |
payment |
authSchemes[{ scheme: "x402" }] |
- SKILL.md → OpenAPI: Each endpoint becomes a path operation. A
402response is added with the price. - OpenAPI → SKILL.md: Each path operation becomes an endpoint. Prices are provided via a pricing map.
SKILL.md uses the x402 protocol for payments. The flow:
Agent Skill Server Facilitator
│ │ │
│ 1. Request endpoint │ │
├───────────────────────────────►│ │
│ │ │
│ 2. HTTP 402 + PaymentRequired │ │
│◄───────────────────────────────┤ │
│ │ │
│ 3. Sign payment │ │
│ (local, non-custodial) │ │
│ │ │
│ 4. Retry with X-PAYMENT header│ │
├───────────────────────────────►│ │
│ │ 5. Verify + settle │
│ ├──────────────────────────────►│
│ │ │
│ │ 6. Confirmation │
│ │◄──────────────────────────────┤
│ │ │
│ 7. Response (200) │ │
│◄───────────────────────────────┤ │
- Non-custodial: The agent signs a payment authorization locally. The facilitator settles on-chain. No party holds funds.
- Atomic: On Stellar, settlement uses a transaction with multiple payment operations. On Base, a Solidity contract splits in a single transaction.
- Gasless: The facilitator covers gas fees. The agent and seller pay zero gas.
A SKILL.md can be a standalone file or part of a skill package:
project/
└── SKILL.md
skill-name/
├── SKILL.md # Required
├── references/ # Loaded on demand
│ ├── api-docs.md
│ └── examples.md
├── scripts/ # Executable utilities
│ └── validate.sh
└── assets/ # Output resources
└── template.html
project/
├── SKILL.md # Root skill (the API itself)
└── skills/ # Agent skills that use the API
├── weather-helper/
│ └── SKILL.md
└── forecast-analyst/
└── SKILL.md
| Rule | Field | Description |
|---|---|---|
MISSING_NAME |
name |
Name is required |
INVALID_NAME |
name |
Must match ^[a-z0-9][a-z0-9_-]*$ |
MISSING_DESCRIPTION |
description |
Description is required |
MISSING_BASE_URL |
base_url |
Required when endpoints are present |
INVALID_BASE_URL |
base_url |
Must be a valid URL |
MISSING_PAYMENT |
payment |
Required when endpoints are present |
MISSING_NETWORKS |
payment.networks |
At least one network config required |
INVALID_NETWORK |
payment.networks[].network |
Must be a valid PaymentNetwork |
MISSING_PAY_TO |
payment.networks[].payTo |
Recipient address required for each network |
MISSING_ENDPOINTS |
endpoints |
At least one endpoint required (unless type: SKILL) |
INVALID_PATH |
endpoints[].path |
Must start with / |
INVALID_METHOD |
endpoints[].method |
Must be a valid HttpMethod |
INVALID_PRICE |
endpoints[].priceUsdc |
Must match ^\d+(\.\d+)?$ or be "dynamic" |
INVALID_DURATION |
endpoints[].duration |
Must match ^\d+(m|h|d|y)$ |
INVALID_DELIVERY_MODE |
endpoints[].deliveryMode |
Must be: sync, polling, webhook |
MISSING_AUTH_METHOD |
auth.method |
Required when auth is specified |
INVALID_LOGIN_ENDPOINT |
auth.loginEndpoint |
Must start with / |
DUPLICATE_ENDPOINT |
endpoints[] |
Duplicate {method} {path} |
| Rule | Field | Description |
|---|---|---|
MISSING_VERSION |
version |
Recommended for published skills |
INVALID_VERSION |
version |
Should follow semver |
MISSING_TAGS |
tags |
Recommended for discovery |
TOO_MANY_TAGS |
tags |
Max 20 tags |
UNRECOGNIZED_ADDRESS |
payment.networks[].payTo |
Address doesn't match known formats |
UNKNOWN_PRICING_MODEL |
pricingModel |
Unknown pricing model value |
UNNECESSARY_FIELD |
endpoints[].estimatedPriceUsdc |
Only meaningful when priceUsdc is "dynamic" |
MISSING_ESTIMATE |
endpoints[].estimatedPriceUsdc |
Dynamic pricing without estimate — agents cannot budget |
The canonical JSON Schema for SKILL.md frontmatter validation is available at:
https://skillmd.dev/schema/v2.json
And programmatically via:
import { SKILLMD_JSON_SCHEMA } from '@402md/skillmd'The schema uses JSON Schema Draft 2020-12 and sets additionalProperties: true for extensibility.
| Feature | Anthropic Skills | 402md SKILL.md | Status |
|---|---|---|---|
name |
Required | Required | Compatible |
description |
Required (trigger phrases) | Required (any format) | Superset |
version |
Optional | Optional | Compatible |
license |
Optional | Optional | Compatible |
allowed-tools |
Optional | Optional | Compatible |
payment |
Not supported | Optional/Required | Extension |
endpoints |
Not supported | Optional/Required | Extension |
base_url |
Not supported | Conditional | Extension |
type |
Implicit (always skill) | Explicit enum | Extension |
tags |
Not supported | Optional | Extension |
author |
Not supported | Optional | Extension |
| Body as instructions | Yes | Yes (all types) | Compatible |
| Body as documentation | Not typical | Yes (API types) | Superset |
references/ directory |
Supported | Supported | Compatible |
scripts/ directory |
Supported | Supported | Compatible |
assets/ directory |
Supported | Supported | Compatible |
Any valid Anthropic Claude Code skill is a valid SKILL.md. The 402md parser accepts Anthropic skills without modification. Additional fields (payment, endpoints, etc.) are extensions that enable payment and API discovery.
The recommended MIME type for SKILL.md files is:
text/markdown; variant=skillmd
When served over HTTP, the Content-Type header SHOULD be text/markdown.
Skills can be discovered through multiple channels:
| Channel | Mechanism |
|---|---|
| File system | Read ./SKILL.md or ./skills/*/SKILL.md |
| URL | Fetch https://example.com/SKILL.md |
| GitHub | Raw URL: https://raw.githubusercontent.com/.../SKILL.md |
| npm | Package includes SKILL.md at root |
| A2A | GET /.well-known/agent-card.json (converted from SKILL.md) |
| Registry | Search via @402md/mcp → search_skills tool |
| Marketplace | Browse at https://402.md/marketplace |
- Payment amounts: Agents SHOULD enforce budget limits before making payments.
- Private keys: MUST be stored locally (e.g.,
~/.402md/wallet.jsonwith mode0600). Private keys MUST NOT be transmitted. - Facilitator trust: The facilitator settles payments but never holds funds. Settlement is atomic and on-chain verifiable.
- Input validation: Parsers MUST validate all fields before use. Untrusted SKILL.md files SHOULD be validated with
validateSkill()before execution. - URL handling:
base_urland endpoint paths MUST be sanitized before constructing request URLs.
The reference implementation is @402md/skillmd:
npm install @402md/skillmdimport {
parseSkillMd,
validateSkill,
generateSkillMd,
toMcpToolDefinitions,
toAgentCard,
toOpenAPI,
SKILLMD_JSON_SCHEMA
} from '@402md/skillmd'| Specification | Relationship |
|---|---|
| x402 Protocol | Payment protocol used by SKILL.md |
| A2A Protocol | Agent discovery. SKILL.md converts to Agent Card. |
| MCP | Agent tool protocol. SKILL.md converts to MCP tools. |
| OpenAPI 3.0 | API description. Bidirectional conversion with SKILL.md. |
| Claude Code Skills | Agent skills. SKILL.md is a compatible superset. |
This is a complete SKILL.md with the instruction layer that enables any agent to use the API autonomously. Notice how every section teaches the agent what to do.
---
name: web-scraper-pro
displayName: Web Scraper Pro
description: >-
This skill should be used when the user asks to "scrape a website",
"extract web content", "crawl a page", "get text from a URL", or
needs HTML-to-structured-data conversion.
High-performance web scraping API with JavaScript rendering.
version: 2.1.0
author: scrapeco
base_url: https://api.scraper.pro
type: API
license: proprietary
payment:
asset: USDC
networks:
- network: stellar
payTo: GABCDEFGHIJKLMNOPQRSTUVWXYZ234567ABCDEFGHIJKLMNOPQRSTUVW
facilitator: https://facilitator.402.md
- network: base
payTo: "0x1234567890abcdef1234567890abcdef12345678"
facilitator: https://facilitator.402.md
endpoints:
- path: /v1/scrape
method: POST
description: Scrape a URL and return structured content
priceUsdc: "0.005"
inputSchema:
type: object
properties:
url:
type: string
format: uri
description: URL to scrape
format:
type: string
enum: [markdown, html, text]
default: markdown
javascript:
type: boolean
default: false
description: Enable JavaScript rendering
required: [url]
outputSchema:
type: object
properties:
content:
type: string
title:
type: string
metadata:
type: object
- path: /v1/screenshot
method: POST
description: Take a full-page screenshot of a webpage
priceUsdc: "0.01"
inputSchema:
type: object
properties:
url:
type: string
format: uri
width:
type: integer
default: 1280
height:
type: integer
default: 800
fullPage:
type: boolean
default: false
required: [url]
outputSchema:
type: object
properties:
imageUrl:
type: string
format:
type: string
sizeBytes:
type: integer
tags: [scraping, web, html, extraction, screenshot]
category: data
sla: "99.9%"
rateLimit: 500/hour
sandbox: https://sandbox.scraper.pro/v1/scrape
---
# Web Scraper Pro
High-performance web scraping API with JavaScript rendering support.
Extract structured content from any webpage or take screenshots.
No API keys needed — pay per request via x402 in USDC.
## Payment Protocol (x402)
This API uses the x402 payment protocol. No API keys or accounts needed.
Payment is per-request in USDC on Stellar or Base.
**How it works:**
1. Make a normal HTTP request to any endpoint below
2. The server responds with HTTP 402 (Payment Required) and a JSON body
containing payment requirements (amount, recipient, network)
3. Sign a USDC transfer authorization with your wallet — non-custodial,
funds only move after the server verifies your signature
4. Retry the same request with the signed payment in the `X-PAYMENT` header
5. The server verifies payment, settles on-chain atomically, and returns the result
**If using @402md/mcp:** Payment is handled automatically. Call the endpoint
via `use_skill` and the MCP server handles the entire 402 → sign → retry flow.
**If calling directly with code:**
```typescript
import { x402Fetch } from '@402md/x402'
const response = await x402Fetch('https://api.scraper.pro/v1/scrape', {
method: 'POST',
body: JSON.stringify({ url: 'https://example.com' }),
stellarSecret: process.env.STELLAR_SECRET,
network: 'stellar'
})
```
## Authentication
No API keys, no accounts, no registration. Authentication IS the payment.
Each request is independently paid via x402. The agent's wallet signature
serves as both authentication and payment authorization.
## Endpoints
### Scrape a URL
**POST /v1/scrape** — $0.005 USDC per call
Extract structured content from any webpage. Returns clean markdown,
HTML, or plain text with metadata.
**Request:**
```json
POST https://api.scraper.pro/v1/scrape
Content-Type: application/json
{
"url": "https://example.com/blog/ai-agents",
"format": "markdown",
"javascript": false
}
```
**Response (200):**
```json
{
"title": "The Rise of AI Agents",
"content": "# The Rise of AI Agents\n\nAI agents are transforming...",
"metadata": {
"author": "Jane Smith",
"publishedAt": "2026-03-10",
"language": "en",
"wordCount": 1423
}
}
```
**Parameters:**
- `url` (required): Full URL to scrape. Must be HTTP or HTTPS.
- `format`: Output format. Options: `markdown` (default), `html`, `text`.
- `javascript`: Set `true` for single-page apps (React, Vue, etc.) that
render content via JavaScript. Adds ~2-5 seconds to response time.
Default: `false`.
**When to use `javascript: true`:**
- The page is a React/Vue/Angular SPA
- Content loads dynamically after page load
- The initial HTML is mostly empty `<div id="root">`
**When to use `javascript: false` (default):**
- Standard blogs, news sites, documentation
- Static HTML pages
- When speed matters more than completeness
### Take a Screenshot
**POST /v1/screenshot** — $0.01 USDC per call
Capture a visual screenshot of any webpage. Returns a hosted image URL.
**Request:**
```json
POST https://api.scraper.pro/v1/screenshot
Content-Type: application/json
{
"url": "https://example.com",
"width": 1280,
"height": 800,
"fullPage": false
}
```
**Response (200):**
```json
{
"imageUrl": "https://cdn.scraper.pro/screenshots/abc123.png",
"format": "png",
"sizeBytes": 245832
}
```
**Parameters:**
- `url` (required): Full URL to screenshot.
- `width`: Viewport width in pixels. Default: `1280`.
- `height`: Viewport height in pixels. Default: `800`.
- `fullPage`: Capture the entire scrollable page, not just the viewport.
Default: `false`.
**Note:** The `imageUrl` is valid for 24 hours. Download or display it promptly.
## Workflow
### Extract text from a webpage
1. Call `POST /v1/scrape` with `{ "url": "...", "format": "markdown" }`
2. Cost: $0.005. Confirm with user if they haven't pre-approved spending.
3. Return the `content` field to the user.
### Scrape a JavaScript-heavy page (SPA)
1. First try without JavaScript: `{ "url": "...", "javascript": false }`
2. If the content is empty or just boilerplate, retry with `"javascript": true`
3. Total cost if retry needed: $0.01 (two calls)
### Get a visual snapshot of a page
1. Call `POST /v1/screenshot` with the URL
2. Cost: $0.01
3. Display the `imageUrl` to the user
### Compare content across multiple pages
1. Call `POST /v1/scrape` for each URL
2. Cost: $0.005 × number of URLs
3. Tell the user total cost before starting: "This will cost $X for Y pages"
4. Wait for user confirmation, then execute all calls
## Error Handling
| Status | Meaning | What to do |
|--------|---------|------------|
| 400 | Invalid input | Check that `url` is a valid HTTP/HTTPS URL. Show error to user. |
| 402 | Payment Required | Normal x402 flow — handled automatically by @402md/x402 or MCP. |
| 403 | Insufficient funds | Tell user: "Wallet balance too low. Fund your wallet to continue." |
| 404 | URL not reachable | The target URL returned 404. Tell user the page doesn't exist. |
| 429 | Rate limited | Wait 60 seconds and retry once. Max 500 requests/hour. |
| 500 | Server error | Retry once after 5 seconds. If still failing, tell user. |
| 504 | Timeout | The page took too long to load. Try with `javascript: false`. |
## Pricing Summary
| Endpoint | Method | Price | Description |
|----------|--------|-------|-------------|
| `/v1/scrape` | POST | $0.005 | Extract content from URL |
| `/v1/screenshot` | POST | $0.01 | Capture visual screenshot |
**Cost examples:**
- Scrape 1 article: $0.005
- Scrape 10 articles: $0.05
- Screenshot + scrape of same page: $0.015
- Scrape SPA with JS retry: $0.01
## Sandbox (Free Testing)
Test the scrape endpoint for free (limited to example.com):
```
POST https://sandbox.scraper.pro/v1/scrape
{ "url": "https://example.com" }
```
No payment required. Use this to verify your integration works before
making paid calls.- Added
pricingModelfield:fixed,dynamic,subscription,cart,free - Added
authblock withwallet-signaturemethod for subscription-based identity - Added
estimatedPriceUsdcfor dynamic pricing budget guidance - Added
durationfield for subscription endpoints (e.g.,"30d") - Added
deliveryModefield:sync,polling,webhook priceUsdcnow accepts"dynamic"for server-determined pricing- Expanded Skill Profiles with Product/Cart, Subscription, and Service patterns
- Added examples directory with complete SKILL.md for each profile type
- Restructured
payment.networksfrom string array toNetworkConfig[]objects - Each network now co-locates
network,payTo, andfacilitator - Removed top-level
payment.payTo,payment.payToEvm, andpayment.facilitator - Parser maintains backward compatibility with v2.0 flat format
- Added
paymentblock with multi-network support - Added
endpoints[].inputSchemaandoutputSchema(JSON Schema) - Added
typeenum withSKILLvalue for pure agent instructions - Added
allowed-toolsfor Anthropic Claude Code compatibility - Added
licensefield - Added
sandbox,sla,rateLimitfields - Added
displayNamefield - Formalized compatibility with Anthropic skill format
- Published JSON Schema at
https://skillmd.dev/schema/v2.json
- Basic frontmatter:
name,description,base_url,type - Endpoints with
pricefield (mapped topriceUsdcin v2) - No payment block (defaults to Base/USDC)