Karon Web Access API Documentation
Base URL: https://api.karonlabs.net
Karon Web Access API is a production API that helps AI agents read and organize public knowledge such as official documentation, standards, papers, and technical references.
Verified Contract
This document reflects the live OpenAPI specification, production server/models.py, production CreditPolicy, and live smoke calls as of June 13, 2026. It covers only the public contract required by regular users and excludes internal operations, administration, security research routes, and internal diagnostic fields.
| Status | Endpoints | Notes |
|---|---|---|
| Core | /v1/agent/browse, /v1/fetch | Primary routes for AI agents to read public knowledge. A Bearer API key is required. |
| Supporting | /v1/watch/snapshot, /v1/watch/diff, /v1/watch/list, /v1/credits | Used for change detection and account status checks. A Bearer API key is required. |
| Public | /health, /v1/pricing | Available without authentication. |
| Get Started | Google sign-in and free key issuance | New Gmail users receive a free Enterprise-tier API key with 810,000 credits. Signing in again preserves the existing key and balance. |
Quickstart
Linux/macOS — Bash
curl -sS -X POST "https://api.karonlabs.net/v1/agent/browse" \
-H "Authorization: Bearer __YOUR_API_KEY__" \
-H "Content-Type: application/json" \
-d '{
"url": "https://example.com",
"extract": "markdown",
"readability": true
}'
Windows — PowerShell
Paste this directly into your current PowerShell prompt. Do not wrap it in another powershell -Command or pwsh -Command invocation.
if (-not $env:KARON_API_KEY) { throw "The KARON_API_KEY environment variable is required." }
$body = @{
url = "https://example.com"
} | ConvertTo-Json -Compress
$request = @{
Uri = "https://api.karonlabs.net/v1/agent/browse"
Method = "Post"
Headers = @{ Authorization = "Bearer $env:KARON_API_KEY" }
ContentType = "application/json; charset=utf-8"
Body = $body
}
Invoke-RestMethod @request
/v1/agent/browse is the primary endpoint for AI agents. Use it when you need content-focused text, markdown, html, json, or pruned output instead of raw HTML.
Authentication
Use the following header with endpoints that require an API key. The public pricing endpoint and health check do not require authentication.
Authorization: Bearer __YOUR_API_KEY__
POST /v1/agent/browse
Converts a public web page into content suitable for AI processing. It uses browser fallback when dynamic rendering is required. Check timing and cost_credits in the response for the processing path and cost.
| Field | Default | Description |
|---|---|---|
| url required | - | Public URL to read. |
| extract | text | text, markdown, html, json, pruned |
| selector | - | Extracts only the specified CSS selector. |
| wait_selector | - | Waits for a specific element to render during browser fallback. |
| wait_timeout_ms | 30000 | Range: 1000-60000ms. |
| full_access | false | Skips the lightweight/cache path and forces browser rendering. |
| session_id | - | Links cookies and session flow across consecutive requests. |
| auto_links | false | Also returns a list of absolute HTTP/HTTPS links from the page. |
| readability | true | Applies content-focused cleanup. Test false for list, search, and portal pages. |
| json_schema | - | Used only with extract: "json". |
| json_prompt | - | Used only with extract: "json"; maximum 1,000 characters. |
{
"success": true,
"url": "https://example.com",
"rid": "<request-id>",
"cost_credits": 0,
"your_credits": null,
"error": null,
"timing": {
"total_ms": 466,
"cache_hit": false,
"curl": true
},
"content": "# Example Domain\n\nThis domain is for use in documentation examples without needing permission. Avoid use in operations.\n\n[Learn more](https://iana.org/domains/example)",
"content_len": 167,
"structured_data": null,
"extract_mode": "markdown",
"links": null,
"warning": "extracted_content_too_short",
"page_title": "Example Domain",
"page_description": null
}
This example shows a call to https://example.com with a user API key. rid, timing, cost_credits, and your_credits may vary by account policy and cache state. Operational detail fields are omitted from the example.
Structured Extraction
extract: "json" attempts to structure requested fields from the retrieved public content. json_schema and json_prompt are valid only in JSON mode.
curl -sS -X POST "https://api.karonlabs.net/v1/agent/browse" \
-H "Authorization: Bearer __YOUR_API_KEY__" \
-H "Content-Type: application/json" \
-d '{
"url": "https://example.com",
"extract": "json",
"json_prompt": "Extract the page title and purpose.",
"json_schema": {
"type": "object",
"properties": {
"title": { "type": "string" },
"purpose": { "type": "string" }
}
}
}'
{
"success": true,
"url": "https://example.com",
"rid": "<request-id>",
"cost_credits": 6,
"your_credits": "<account-dependent>",
"error": null,
"timing": {
"total_ms": 2284,
"cache_hit": false,
"curl": true
},
"content": "",
"content_len": 0,
"structured_data": {
"title": "Example Domain",
"purpose": "This domain is for use in documentation examples without needing permission. Avoid use in operations."
},
"extract_mode": "json",
"links": null,
"warning": null,
"page_title": "Example Domain"
}
JSON structured extraction currently uses the local SuperGemma backend in production. The additional JSON cost applies only when a structured result is produced. For regular users, structured extraction +5 is added to cache/curl 1. Administrator or internal verification keys may show a cost_credits value of 0.
POST /v1/fetch
Use this endpoint when you need a public URL's HTML body, status code, and headers.
| Field | Default | Description |
|---|---|---|
| url required | - | Public URL to fetch. |
| wait_selector | - | CSS selector to wait for during browser fallback. |
| wait_timeout_ms | 30000 | Range: 1000-60000ms. |
| session_id | - | Maintains a session across consecutive requests. |
| cache_scope | global | Either global or session. |
| fallback | true | Allows browser fallback when the lightweight request is insufficient. |
curl -sS -X POST "https://api.karonlabs.net/v1/fetch" \
-H "Authorization: Bearer __YOUR_API_KEY__" \
-H "Content-Type: application/json" \
-d '{"url": "https://example.com"}'
{
"success": true,
"url": "https://example.com",
"rid": "<request-id>",
"cost_credits": 0,
"your_credits": null,
"error": null,
"timing": {
"total_ms": 0,
"full_access": false,
"cache_hit": true
},
"status_code": 200,
"body": "<!doctype html><html lang=\"en\"><head><title>Example Domain</title>...",
"body_len": 559,
"session_id": "https://example.com",
"headers": {
"content-type": "text/html"
},
"set_cookies": null
}
POST Watch API
Saves snapshots of public pages and compares them with previous snapshots. Watch uses the browse flow internally, so its cost follows the browse policy.
| Endpoint | Request Fields | Key Response Fields |
|---|---|---|
| /v1/watch/snapshot | url, extract, readability, json_schema, json_prompt, ttl_days | snapshot_id, content_hash, content_len, previous_snapshot, diff |
| /v1/watch/diff | url, extract, readability, json_schema, json_prompt | changed, current_snapshot_id, previous_snapshot_id, change_ratio, diff_text |
| /v1/watch/list | - | total, urls |
curl -sS -X POST "https://api.karonlabs.net/v1/watch/snapshot" \
-H "Authorization: Bearer __YOUR_API_KEY__" \
-H "Content-Type: application/json" \
-d '{"url": "https://example.com", "extract": "text", "ttl_days": 1}'
{
"success": true,
"url": "https://example.com",
"snapshot_id": "<snapshot-id>",
"content_hash": "<sha256>",
"content_len": 127,
"previous_snapshot": null,
"diff": null,
"cost_credits": 0,
"error": null
}
curl -sS -X POST "https://api.karonlabs.net/v1/watch/diff" \
-H "Authorization: Bearer __YOUR_API_KEY__" \
-H "Content-Type: application/json" \
-d '{"url": "https://example.com", "extract": "text"}'
{
"success": true,
"url": "https://example.com",
"changed": false,
"current_snapshot_id": "<snapshot-id>",
"previous_snapshot_id": "<snapshot-id>",
"current_content_len": 127,
"previous_content_len": 127,
"diff_text": "",
"cost_credits": 0,
"error": null
}
curl -sS "https://api.karonlabs.net/v1/watch/list" \ -H "Authorization: Bearer __YOUR_API_KEY__"
{
"total": 1,
"urls": [
{
"url": "https://example.com",
"extract_mode": "text",
"content_hash": "<sha256>",
"content_len": 127,
"last_snapshot_at": "<iso8601>"
}
]
}
/v1/watch/snapshot and /v1/watch/diff save a snapshot with each call. snapshot_id, content_hash, and last_snapshot_at vary by account and call time.
GET /v1/credits
Returns the remaining credits, tier, and rate limit for your account.
curl -sS "https://api.karonlabs.net/v1/credits" \ -H "Authorization: Bearer __YOUR_API_KEY__"
{
"name": "<account-name>",
"credits_remaining": "<account-dependent>",
"tier": "free",
"tier_name": "Free",
"credits_included": 5000,
"rate_limit": 30
}
GET /v1/pricing
Returns the current public pricing tiers without authentication. The current live tiers are Free, Starter, Growth, Scale, and Enterprise.
{
"tiers": {
"free": { "price_usd": 0, "credits": 5000, "rate_limit": 30, "daily_limit": 1000, "name": "Free" },
"starter": { "price_usd": 29, "credits": 10000, "rate_limit": 60, "daily_limit": 2000, "name": "Starter" }
}
}
GET /health
Checks service status. The current live response returns status: "ok" and a version value.
{
"status": "ok",
"version": "0.2.0",
"timestamp": "<iso8601>",
"court_rig": {
"ready": false,
"last_checked": "",
"details": {}
}
}
Credit Policy
| Path | Cost | Notes |
|---|---|---|
| cache/curl | cache/curl 1 | Successful cached response or lightweight fetch/browse |
| browser | browser 10 | Successful browser-based fallback |
| json | structured extraction +5 | A structured result is produced with extract: "json" |
| watch | inherits browse policy | Snapshot and diff follow the cost of the internal browse call. |
The actual charge may vary depending on request failure, client cancellation, and when a browser job completes. Use the response's cost_credits value as the authoritative charge.
MCP Clients
Karon MCP is a connection layer for using Karon API directly from MCP hosts such as Claude Code, Cursor, and Codex. The REST API is the canonical contract; MCP wraps that contract in a small tool surface.
Two public MCP tools are available.
browse: Calls/v1/agent/browseto retrieve one URL asmarkdown,text, orhtml.credits: Calls/v1/creditsto check account credits and tier information.
KARON_API_KEY=__YOUR_API_KEY__ uvx --refresh karon-mcp
Errors and Limits
| Status | Meaning | Action |
|---|---|---|
| 400 | Invalid request body or URL | Check JSON syntax, the required url, and the public HTTP/HTTPS URL requirement. |
| 401 | Missing or invalid API key | Check the Authorization Bearer value. |
| 403 | Account or edge policy restriction | Preserve the response body and X-Request-ID, then check account status, API key permissions, and the requested endpoint. |
| 413 | Request body size limit exceeded | Reduce the body and send a new request. Do not retry the same body unchanged. |
| 422 | Request passed Shield but failed schema validation | Send url as a string and check the allowed values and ranges for other fields. |
| 429 | Rate limit or credit limit | If the response includes Retry-After, wait for that interval before retrying or adjust your plan. |
| 503 | Temporary processing capacity shortage | If the response includes Retry-After, wait for that interval before retrying. |
| Other 5xx | Karon processing or upstream site access failure | Record the error type and request ID from the response body, then apply your retry policy. |
Shield Error Response v2 (Optional)
To receive only Shield Wall and request schema errors in v2 format, send exactly one Karon-Error-Version: 2 header. A v2 response uses application/problem+json and includes type, title, status, detail, error, and retryable in that order.
| Status | error | retryable | Retry-After |
|---|---|---|---|
| 400 | bad_request | false | none |
| 413 | payload_too_large | false | none |
| 422 | validation_error | false | none |
| 429, 503 | system_busy | true | preserve dynamic value |
For 400, 413, and 422, correct the request instead of retrying it unchanged. For 429 and 503, follow retryable: true and the dynamic Retry-After value. A missing, empty, unsupported, comma-combined, or duplicated header value receives the existing v1 response. Authentication, credit, and general route errors are not covered by v2.
Browser preflight also applies the global QPS limit first. Even an OPTIONS request for an allowed Origin and the v2 header token receives the existing v1 429 when the global limit is reached. Only requests that pass the limit are delegated to the existing CORS handling.
Do not infer the target site's WAF product or blocking cause from the status code alone. Review the response body, request ID, and timing together to distinguish API authentication, Karon processing, and upstream site access failures.