# 402 Index API

Public API for the 402 Index — a protocol-agnostic directory of paid APIs (L402, x402, MPP) for AI agents.

Base URL: https://402index.io

---

## GET /api/v1/services

Search and filter paid API services

**Parameters:**

| Name | In | Type | Required | Description |
|------|----|------|----------|-------------|
| protocol | query | enum: L402, x402, MPP | No | Filter by payment protocol |
| category | query | string | No | Filter by category (prefix match — "crypto" matches "crypto/nft") |
| health | query | enum: healthy, degraded, down, unknown | No | Filter by health status |
| source | query | enum: bazaar, satring, l402apps, sponge, l402directory, mpp, discovery, self-registered | No | Filter by data source |
| q | query | string | No | Hybrid semantic + LIKE search. When q is present and no explicit sort is specified, results are re-ranked using a 5-tier composite: (A) exact name match, (B) LIKE name, (C) LIKE description, (D) cosine similarity from embeddings, (E) default order. Semantic search requires embeddings to be backfilled. Falls back to LIKE-only if the embedding service is unavailable. |
| featured | query | boolean | No | Only return featured services |
| sort | query | enum: name, price, latency, uptime, reliability | No | Sort field |
| order | query | enum: asc, desc | No | Sort order |
| payment_valid | query | boolean | No | Only x402 services with verified payment requirements |
| verified | query | boolean | No | Only payment-verified services (x402: valid payment headers, L402/MPP: healthy). Domain-verified services ranked first. Recommended for agents making payment decisions. |
| l402_format | query | enum: v2_tlv, v1_binary, v0_text, json, unknown | No | Filter L402 endpoints by macaroon token format |
| lnget_compatible | query | boolean | No | Filter L402 endpoints by lnget client compatibility |
| limit | query | integer | No | Results per page |
| offset | query | integer | No | Pagination offset |

**Responses:**

- **200**: Paginated list of services
- **402**: L402 payment required (rate limit exceeded). The WWW-Authenticate header contains a Lightning invoice.

---

## GET /api/v1/services/{id}

Get full details for a single service

**Parameters:**

| Name | In | Type | Required | Description |
|------|----|------|----------|-------------|
| id | path | string | Yes | Service ID |

**Responses:**

- **200**: Service with health check history
- **404**: Service not found

---

## PATCH /api/v1/services/{id}

Edit a listing by verified domain owner

**Parameters:**

| Name | In | Type | Required | Description |
|------|----|------|----------|-------------|
| id | path | string | Yes | Service ID |

**Request Body:**

| Name | Type | Required | Description |
|------|------|----------|-------------|
| domain | string | Yes | Verified domain |
| verification_token | string | Yes | Token from domain claim (ongoing credential) |
| name | string | No |  |
| description | string | No |  |
| category | string | No |  |
| price_usd | number | No |  |
| price_sats | integer | No |  |
| payment_asset | string | No |  |
| payment_network | string | No |  |

**Responses:**

- **200**: Service updated
- **400**: Missing domain/token, no valid fields, or field exceeds max length
- **403**: Invalid token, unverified domain, or domain mismatch
- **404**: Service not found

---

## DELETE /api/v1/services/{id}

Soft-delete a listing by verified domain owner

**Parameters:**

| Name | In | Type | Required | Description |
|------|----|------|----------|-------------|
| id | path | string | Yes | Service ID |

**Request Body:**

| Name | Type | Required | Description |
|------|------|----------|-------------|
| domain | string | Yes | Verified domain |
| verification_token | string | Yes | Token from domain claim (ongoing credential) |

**Responses:**

- **200**: Service soft-deleted (or already deleted)
- **400**: Missing domain or verification_token
- **403**: Invalid token, unverified domain, or domain mismatch
- **404**: Service not found

---

## POST /api/v1/services/bulk-delete

Bulk soft-delete listings by verified domain owner

**Request Body:**

| Name | Type | Required | Description |
|------|------|----------|-------------|
| ids | array | Yes | Service IDs to delete (max 25) |
| domain | string | Yes | Verified domain |
| verification_token | string | Yes | Token from domain claim |

**Responses:**

- **200**: Bulk delete results
- **400**: Missing fields, ids not an array, empty ids, or exceeds 25 limit
- **403**: Invalid token or unverified domain

---

## GET /api/v1/health

System health and sync status

**Responses:**

- **200**: Health status with endpoint counts, protocol breakdown, and sync timestamps

---

## GET /api/v1/categories

List all categories with per-protocol endpoint counts

**Responses:**

- **200**: Category tree with L402/x402/MPP breakdown

---

## GET /api/v1/export.csv

Export full directory as CSV (L402 payment required)

**Responses:**

- **200**: CSV file download
- **402**: L402 payment required (500 sats). Pay the Lightning invoice to download.

---

## GET /api/v1/stats/snapshots

Historical daily snapshots of directory statistics

**Parameters:**

| Name | In | Type | Required | Description |
|------|----|------|----------|-------------|
| days | query | integer | No | Number of days of history |

**Responses:**

- **200**: Array of daily snapshots

---

## POST /api/v1/register

Register a paid API endpoint (L402, x402, or MPP)

**Request Body:**

| Name | Type | Required | Description |
|------|------|----------|-------------|
| url | string | Yes | The endpoint URL to register |
| name | string | Yes | Display name for the service |
| protocol | enum: L402, x402, MPP | Yes | Payment protocol (case-insensitive) |
| description | string | No |  |
| category | string | No |  |
| contact_email | string | No |  |
| http_method | enum: GET, POST, PUT, DELETE | No |  |
| probe_body | string | No | JSON body for health check probes |
| price_sats | integer | No |  |
| price_usd | number | No |  |
| payment_asset | string | No |  |
| payment_network | string | No |  |
| provider | string | No |  |

**Responses:**

- **201**: Service registered (pending review)
- **400**: Missing required fields or invalid input
- **422**: Verification failed — endpoint did not return a valid protocol challenge
- **429**: Rate limited (10 registrations per hour per IP)

---

## GET /api/v1/opportunities

Ecosystem gap analysis

**Responses:**

- **200**: Identified gaps in protocol and category coverage

---

## GET /feed.xml

RSS 2.0 feed of indexed services

**Parameters:**

| Name | In | Type | Required | Description |
|------|----|------|----------|-------------|
| protocol | query | enum: L402, x402, MPP | No | Filter by protocol |
| health | query | enum: healthy, degraded, down | No | Filter by health status |
| type | query | enum: new | No | "new" for services added in the last 7 days |

**Responses:**

- **200**: RSS/XML feed with l402:service namespace extensions

---

## POST /api/v1/webhooks

Register a webhook for real-time notifications

**Request Body:**

| Name | Type | Required | Description |
|------|------|----------|-------------|
| url | string | Yes | HTTPS callback URL |
| secret | string | Yes | Shared secret for HMAC-SHA256 signing (min 16 chars) |
| events | string | No | Comma-separated: service.new, service.health_changed, service.down |
| protocol_filter | enum: L402, x402, MPP | No |  |

**Responses:**

- **201**: Webhook registered

---

## GET /api/v1/webhooks/{id}

Check webhook status

**Parameters:**

| Name | In | Type | Required | Description |
|------|----|------|----------|-------------|
| id | path | string | Yes |  |
| X-Webhook-Secret | header | string | Yes |  |

**Responses:**

- **200**: Webhook details
- **401**: Missing or invalid X-Webhook-Secret
- **404**: Webhook not found

---

## DELETE /api/v1/webhooks/{id}

Delete a webhook

**Parameters:**

| Name | In | Type | Required | Description |
|------|----|------|----------|-------------|
| id | path | string | Yes |  |
| X-Webhook-Secret | header | string | Yes |  |

**Responses:**

- **200**: Webhook deleted
- **401**: Missing or invalid X-Webhook-Secret
- **404**: Webhook not found

---

## POST /api/v1/claim

Initiate a domain claim for provider listing edits

**Request Body:**

| Name | Type | Required | Description |
|------|------|----------|-------------|
| domain | string | Yes | Hostname to claim (e.g. "api.example.com"). No protocol, path, or port. |
| contact_email | string | No | Optional contact email for the provider |

**Responses:**

- **200**: Existing pending claim updated with new token
- **201**: New domain claim created
- **400**: Invalid domain format
- **409**: Domain already verified by another provider
- **429**: Rate limited (10 claims per hour per IP)

---

## POST /api/v1/claim/revoke

Revoke a verified domain claim

**Request Body:**

| Name | Type | Required | Description |
|------|------|----------|-------------|
| domain | string | Yes | Verified domain to revoke |
| verification_token | string | Yes | Current token (proves ownership) |

**Responses:**

- **200**: Claim revoked
- **400**: Missing domain or verification_token
- **403**: Invalid token or no verified claim for this domain
- **404**: No claim found for this domain

---

## POST /api/v1/admin/domains/{domain}/reset

Reset a domain verification token (admin only)

**Parameters:**

| Name | In | Type | Required | Description |
|------|----|------|----------|-------------|
| domain | path | string | Yes | Domain to reset (e.g. api.example.com) |

**Responses:**

- **200**: Domain reset. Returns new token, hash, and instructions.
- **401**: Missing or invalid admin authorization
- **404**: No claim found for this domain

---

## POST /api/v1/claim/verify

Verify a pending domain claim

**Request Body:**

| Name | Type | Required | Description |
|------|------|----------|-------------|
| domain | string | Yes | Domain to verify |

**Responses:**

- **200**: Domain verified successfully
- **400**: Invalid domain format
- **404**: No pending claim found for this domain
- **409**: Domain already verified
- **410**: Claim expired (72-hour window). Initiate a new claim.
- **422**: Verification failed (token mismatch, redirect, unreachable, SSRF blocked, or response too large)
