# SEOAgent.one API Documentation

Base URL: `https://api.seoagent.one`

---

## Getting Started

1. **Sign up** at [seoagent.one/login](https://seoagent.one/login) — no credit card required.
2. **Create an API key** from the Dashboard under API Keys. Your key will look like `uc_live_...`.
3. **Make your first request:**

```bash
curl -X POST https://api.seoagent.one/v1/check \
  -H "Authorization: Bearer uc_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{"url":"https://example.com"}'
```

You get **100 free credits** on signup. Each single URL check costs 1 credit.

---

## Authentication

All API requests require a Bearer token in the `Authorization` header:

```
Authorization: Bearer uc_live_...
```

API keys can be created and revoked from the Dashboard. Keys that are revoked or expired will return a `401` error.

---

## Credits

Every API call that checks URLs costs credits. 1 URL check = 1 credit. Multi-bot analysis = 6 credits (checks 6 user agent profiles).

### Check Balance

```
GET /v1/credits
```

**Example:**

```bash
curl https://api.seoagent.one/v1/credits \
  -H "Authorization: Bearer uc_live_YOUR_KEY"
```

**Response:**

```json
{
  "balance": 9450
}
```

If you don't have enough credits for a request, the API returns `402` with:

```json
{
  "error": "Insufficient credits",
  "required": 100,
  "operation": "check.bulk"
}
```

---

## URL Checking

### Single URL Check

Check a single URL with full redirect chain tracking.

```
POST /v1/check
```

**Cost:** 1 credit

**Request body:**

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `url` | string | Yes | URL to check (max 2048 chars) |
| `user_agent` | string | No | User agent profile (e.g. `"googlebot_desktop"`, `"chrome"`) |
| `country` | string | No | Country code for geo-location testing (e.g. `"US"`, `"DE"`) |
| `max_redirects` | number | No | Maximum redirects to follow (0-50) |
| `extract_content` | boolean | No | Extract title, h1, canonical, robots meta from final page |
| `http_version` | string | No | HTTP version to use (e.g. `"1.1"`, `"2"`) |

**Example:**

```bash
curl -X POST https://api.seoagent.one/v1/check \
  -H "Authorization: Bearer uc_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://example.com",
    "user_agent": "googlebot_desktop",
    "country": "US",
    "extract_content": true
  }'
```

**Response:**

```json
{
  "input_url": "https://example.com",
  "final_url": "https://www.example.com/",
  "final_status": 200,
  "num_redirects": 1,
  "total_latency_ms": 342,
  "chain": [
    {
      "url": "https://example.com",
      "status": 301,
      "location": "https://www.example.com/",
      "latency_ms": 120
    },
    {
      "url": "https://www.example.com/",
      "status": 200,
      "latency_ms": 222
    }
  ],
  "content": {
    "title": "Example Domain",
    "h1": "Example Domain",
    "canonical": "https://www.example.com/",
    "robots": "index, follow",
    "lang": "en"
  }
}
```

---

### Compare Check

Check a URL with two user agent profiles side by side (the specified one and a baseline) to quickly spot differences.

```
POST /v1/check/compare
```

**Cost:** 2 credits

**Request body:**

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `url` | string | Yes | URL to check |
| `user_agent` | string | No | Primary user agent profile |
| `country` | string | No | Country code for geo-location testing |
| `extract_content` | boolean | No | Extract page content metadata |

**Example:**

```bash
curl -X POST https://api.seoagent.one/v1/check/compare \
  -H "Authorization: Bearer uc_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://example.com",
    "user_agent": "googlebot_desktop",
    "extract_content": true
  }'
```

---

### Multi-Bot Analysis

Fire a URL through multiple user agent profiles simultaneously to detect when sites serve different content to bots vs humans.

```
POST /v1/check/cloak
```

**Cost:** 6 credits (default 6 profiles)

**Request body:**

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `url` | string | Yes | URL to check |
| `country` | string | No | Country code for geo-location testing |
| `profiles` | string[] | No | Specific profiles to use (max 20). Defaults to 6 standard profiles. |

**Example:**

```bash
curl -X POST https://api.seoagent.one/v1/check/cloak \
  -H "Authorization: Bearer uc_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://example.com",
    "country": "US"
  }'
```

---

### Bulk Check

Submit up to 5,000 URLs for asynchronous processing. Returns a job ID to poll for results.

```
POST /v1/check/bulk
```

**Cost:** 1 credit per URL

**Request body:**

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `urls` | string[] | Yes | Array of URLs to check (1-5,000) |
| `user_agent` | string | No | User agent profile |
| `country` | string | No | Country code for geo-location testing |
| `extract_content` | boolean | No | Extract page content metadata |
| `compare_httpstatus` | boolean | No | Compare HTTP status codes |
| `http_version` | string | No | HTTP version to use |
| `project_name` | string | No | Name for auto-created project (max 200 chars) |
| `label` | string | No | Label for this checkpoint (max 200 chars) |

**Example:**

```bash
curl -X POST https://api.seoagent.one/v1/check/bulk \
  -H "Authorization: Bearer uc_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "urls": [
      "https://example.com/page-1",
      "https://example.com/page-2",
      "https://example.com/page-3"
    ],
    "user_agent": "googlebot_desktop",
    "country": "US",
    "project_name": "example.com audit"
  }'
```

**Response:**

```json
{
  "job_id": "abc123",
  "status": "pending",
  "total_urls": 3,
  "project_id": "proj_abc123",
  "checkpoint_id": "cp_abc123"
}
```

After receiving the `job_id`, poll `GET /v1/jobs/:jobId` until `status` is `"completed"` or `"failed"`.

---

### Bulk Multi-Bot Analysis

Submit up to 5,000 URLs for bulk multi-bot analysis.

```
POST /v1/check/cloak/bulk
```

**Cost:** 6 credits per URL (default 6 profiles)

**Request body:**

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `urls` | string[] | Yes | Array of URLs (1-5,000) |
| `country` | string | No | Country code for geo-location testing |
| `profiles` | string[] | No | Specific profiles to use (max 20) |

**Example:**

```bash
curl -X POST https://api.seoagent.one/v1/check/cloak/bulk \
  -H "Authorization: Bearer uc_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "urls": [
      "https://example.com/page-1",
      "https://example.com/page-2"
    ],
    "country": "US"
  }'
```

---

## Sitemap Discovery

Discover and extract URLs from a domain's sitemap(s). This endpoint is **free** and does not cost any credits.

```
POST /v1/discover-sitemap
```

**Cost:** Free (0 credits)

**Request body:**

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `domain` | string | Yes | Domain to discover sitemaps for (e.g. `"example.com"`) |
| `max_urls` | number | No | Maximum URLs to return (1-5,000, default 1,000) |

**Example:**

```bash
curl -X POST https://api.seoagent.one/v1/discover-sitemap \
  -H "Authorization: Bearer uc_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "domain": "example.com",
    "max_urls": 500
  }'
```

**Response:**

```json
{
  "domain": "example.com",
  "sitemaps_found": ["https://example.com/sitemap.xml"],
  "urls": [
    "https://example.com/",
    "https://example.com/about",
    "https://example.com/contact"
  ],
  "total_urls": 3
}
```

---

## Jobs

Poll for the status and results of bulk jobs.

```
GET /v1/jobs/:jobId
```

**Example:**

```bash
curl https://api.seoagent.one/v1/jobs/abc123 \
  -H "Authorization: Bearer uc_live_YOUR_KEY"
```

**Response (pending):**

```json
{
  "job_id": "abc123",
  "status": "pending",
  "progress": 45,
  "total_urls": 100
}
```

**Response (completed):**

```json
{
  "job_id": "abc123",
  "status": "completed",
  "total_urls": 100,
  "results": [
    {
      "input_url": "https://example.com/page-1",
      "final_url": "https://example.com/page-1",
      "final_status": 200,
      "num_redirects": 0,
      "total_latency_ms": 156,
      "chain": [...],
      "content": { ... }
    }
  ]
}
```

Recommended polling interval: start at 2 seconds, increase to 5 seconds after 30 seconds.

---

## Projects

Projects automatically group bulk checks by domain. Each bulk check creates a checkpoint that tracks changes over time.

### List Projects

```
GET /v1/projects
```

**Example:**

```bash
curl https://api.seoagent.one/v1/projects \
  -H "Authorization: Bearer uc_live_YOUR_KEY"
```

**Response:**

```json
{
  "projects": [
    {
      "id": "proj_abc123",
      "domain": "example.com",
      "name": "example.com audit",
      "createdAt": "2025-01-15T10:00:00Z",
      "updatedAt": "2025-01-20T14:30:00Z"
    }
  ]
}
```

### Get Project

```
GET /v1/projects/:id
```

### List Checkpoints

```
GET /v1/projects/:id/checkpoints
```

**Query parameters:**

| Param | Type | Default | Description |
|-------|------|---------|-------------|
| `limit` | number | 20 | Results per page (1-100) |
| `offset` | number | 0 | Pagination offset |

**Example:**

```bash
curl "https://api.seoagent.one/v1/projects/proj_abc123/checkpoints?limit=10" \
  -H "Authorization: Bearer uc_live_YOUR_KEY"
```

**Response:**

```json
{
  "project_id": "proj_abc123",
  "domain": "example.com",
  "checkpoints": [
    {
      "id": "cp_001",
      "status": "completed",
      "totalUrls": 500,
      "completedCount": 498,
      "failedCount": 2,
      "userAgent": "googlebot_desktop",
      "country": "US",
      "createdAt": "2025-01-20T14:30:00Z"
    }
  ]
}
```

### Diff Checkpoints

Compare two checkpoints to see what changed between crawls.

```
GET /v1/projects/:id/diff?from=CHECKPOINT_ID&to=CHECKPOINT_ID
```

**Query parameters:**

| Param | Type | Required | Description |
|-------|------|----------|-------------|
| `from` | string | No | Older checkpoint ID (defaults to second-latest) |
| `to` | string | No | Newer checkpoint ID (defaults to latest) |

**Example:**

```bash
curl "https://api.seoagent.one/v1/projects/proj_abc123/diff?from=cp_001&to=cp_002" \
  -H "Authorization: Bearer uc_live_YOUR_KEY"
```

**Response:**

```json
{
  "from": { "id": "cp_001", "created_at": "2025-01-15T10:00:00Z" },
  "to": { "id": "cp_002", "created_at": "2025-01-20T14:30:00Z" },
  "summary": {
    "newly_broken": 2,
    "newly_fixed": 1,
    "status_changed": 3,
    "new_urls": 5,
    "removed_urls": 0
  },
  "newly_broken": [
    { "url": "https://example.com/old-page", "previous_status": 200, "current_status": 404 }
  ],
  "newly_fixed": [...],
  "status_changed": [...],
  "new_urls": [...],
  "removed_urls": [...]
}
```

---

## Share Links

Create shareable read-only links to project reports.

### Create Share Link

```
POST /v1/projects/:id/share
```

**Request body:**

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `label` | string | No | Label for the link (max 200 chars) |
| `expires_at` | string | No | ISO 8601 expiration datetime |

**Example:**

```bash
curl -X POST https://api.seoagent.one/v1/projects/proj_abc123/share \
  -H "Authorization: Bearer uc_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "label": "Client report Q1",
    "expires_at": "2025-03-01T00:00:00Z"
  }'
```

**Response:**

```json
{
  "id": "link_abc123",
  "url": "https://seoagent.one/report/TOKEN",
  "token": "TOKEN",
  "label": "Client report Q1",
  "expires_at": "2025-03-01T00:00:00Z",
  "created_at": "2025-01-20T14:30:00Z"
}
```

### List Share Links

```
GET /v1/projects/:id/share
```

**Response:**

```json
{
  "links": [
    {
      "id": "link_abc123",
      "token": "TOKEN",
      "label": "Client report Q1",
      "expiresAt": "2025-03-01T00:00:00Z",
      "createdAt": "2025-01-20T14:30:00Z"
    }
  ]
}
```

### Revoke Share Link

```
DELETE /v1/projects/:id/share/:linkId
```

**Response:**

```json
{
  "success": true
}
```

---

## Profiles

List available user agent profiles for multi-bot analysis.

```
GET /v1/profiles
```

**Example:**

```bash
curl https://api.seoagent.one/v1/profiles \
  -H "Authorization: Bearer uc_live_YOUR_KEY"
```

**Response:**

```json
{
  "profiles": [
    "chrome",
    "googlebot_desktop",
    "googlebot_mobile",
    "bingbot",
    "gptbot",
    "claudebot",
    "chatgpt_user",
    "applebot",
    "yandexbot",
    "baiduspider",
    "duckduckbot",
    "facebookbot",
    "twitterbot",
    "linkedinbot"
  ]
}
```

---

## Error Handling

All errors return a JSON body with an `error` field.

| Status | Meaning | Example |
|--------|---------|---------|
| `400` | Invalid request body or parameters | `{"error": "Validation failed", "details": [...]}` |
| `401` | Missing, invalid, or expired API key | `{"error": "Missing Authorization header. Use: Bearer uc_live_..."}` |
| `402` | Insufficient credits | `{"error": "Insufficient credits", "required": 100}` |
| `404` | Resource not found | `{"error": "Project not found"}` |
| `429` | Rate limit exceeded | `{"error": "Rate limit exceeded"}` |
| `500` | Internal server error | `{"error": "Internal server error"}` |
| `502` | Upstream service error | `{"error": "URL checker service unavailable"}` |

Validation errors (`400`) include a `details` array:

```json
{
  "error": "Validation failed",
  "details": [
    { "path": "url", "message": "Must be a valid URL" },
    { "path": "max_redirects", "message": "Number must be less than or equal to 50" }
  ]
}
```

---

## Rate Limits

| Scope | Limit |
|-------|-------|
| Auth routes (login, signup) | 3-5 requests/minute |
| API key requests | 60 requests/minute (configurable) |

When rate limited, the API returns `429 Too Many Requests`. Back off and retry with exponential backoff.

---

## CLI Usage

SEOAgent also provides an official CLI for terminal-based workflows:

```bash
npx seoagent-cli check https://example.com
npx seoagent-cli bulk check urls.txt --user-agent googlebot_desktop
```

Set your API key via environment variable:

```bash
export SEOAGENT_API_KEY=uc_live_YOUR_KEY
```

Visit the [CLI documentation](https://github.com/seoagent/cli) for full usage details.

---

*This documentation is also available as a [downloadable Markdown file](/api/docs) for use with AI agents and CLI tools.*
