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.

StatusEndpointsNotes
Core/v1/agent/browse, /v1/fetchPrimary 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/creditsUsed for change detection and account status checks. A Bearer API key is required.
Public/health, /v1/pricingAvailable without authentication.
Get StartedGoogle sign-in and free key issuanceNew 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.

FieldDefaultDescription
url required-Public URL to read.
extracttexttext, 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_ms30000Range: 1000-60000ms.
full_accessfalseSkips the lightweight/cache path and forces browser rendering.
session_id-Links cookies and session flow across consecutive requests.
auto_linksfalseAlso returns a list of absolute HTTP/HTTPS links from the page.
readabilitytrueApplies 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.

FieldDefaultDescription
url required-Public URL to fetch.
wait_selector-CSS selector to wait for during browser fallback.
wait_timeout_ms30000Range: 1000-60000ms.
session_id-Maintains a session across consecutive requests.
cache_scopeglobalEither global or session.
fallbacktrueAllows 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.

EndpointRequest FieldsKey Response Fields
/v1/watch/snapshoturl, extract, readability, json_schema, json_prompt, ttl_dayssnapshot_id, content_hash, content_len, previous_snapshot, diff
/v1/watch/diffurl, extract, readability, json_schema, json_promptchanged, 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

PathCostNotes
cache/curlcache/curl 1Successful cached response or lightweight fetch/browse
browserbrowser 10Successful browser-based fallback
jsonstructured extraction +5A structured result is produced with extract: "json"
watchinherits browse policySnapshot 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/browse to retrieve one URL as markdown, text, or html.
  • credits: Calls /v1/credits to check account credits and tier information.
KARON_API_KEY=__YOUR_API_KEY__ uvx --refresh karon-mcp

Errors and Limits

StatusMeaningAction
400Invalid request body or URLCheck JSON syntax, the required url, and the public HTTP/HTTPS URL requirement.
401Missing or invalid API keyCheck the Authorization Bearer value.
403Account or edge policy restrictionPreserve the response body and X-Request-ID, then check account status, API key permissions, and the requested endpoint.
413Request body size limit exceededReduce the body and send a new request. Do not retry the same body unchanged.
422Request passed Shield but failed schema validationSend url as a string and check the allowed values and ranges for other fields.
429Rate limit or credit limitIf the response includes Retry-After, wait for that interval before retrying or adjust your plan.
503Temporary processing capacity shortageIf the response includes Retry-After, wait for that interval before retrying.
Other 5xxKaron processing or upstream site access failureRecord 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.

StatuserrorretryableRetry-After
400bad_requestfalsenone
413payload_too_largefalsenone
422validation_errorfalsenone
429, 503system_busytruepreserve 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.