Developer Documentation

Base URL: https://api.karonlabs.net

Quick Start

curl -X POST https://api.karonlabs.net/v1/fetch \
  -H "Authorization: Bearer __YOUR_API_KEY__" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://example.com"}'

That's it. The API handles common protected-site access workflows with managed sessions, caching, and browser-backed fallback where needed. Compatibility varies by target site, configuration, and account policy.

Authentication

All API endpoints except /v1/pricing and /health require a Bearer token. Use Get API Key to sign up, then send the key in the Authorization header:

Authorization: Bearer __YOUR_API_KEY__

POST /v1/fetch

Fetch a URL and return raw HTML. Automatic access handling with response caching.

Parameters

NameTypeDefaultDescription
urlstring REQUIRED-Target URL (max 8,192 chars)
wait_selectorstring-CSS selector used if the request needs full-access fallback before capturing
wait_timeout_msint10000Selector timeout (1,000 - 30,000 ms)
session_idstring-Share cookies across requests

Response

{
  "success": true,
  "status_code": 200,
  "url": "https://www.nike.com",
  "body": "<!DOCTYPE html>...",
  "body_len": 142857,
  "timing": {
    "total_ms": 62,
    "full_access": false,
    "cache_hit": true
  },
  "cost_credits": 1,
  "headers": { "content-type": "text/html" }
}
Failed requests return "cost_credits": 0. You are never charged for failures.

Credit behavior for /v1/fetch

/v1/fetch first attempts a lightweight HTML fetch. If that succeeds, the request costs 1 credit, even when wait_selector is present. If lightweight fetching cannot complete the request and the API has to use the full-access path successfully, the request costs 10 credits. Response cache hits cost 1 credit for API users. Failed requests cost 0 credits.

Result pathCost
Response cache hit1 credit
Lightweight HTML fetch success1 credit
Full-access fallback success10 credits
Failed request0 credits

Runnable fetch example

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",
    "wait_selector": "body",
    "wait_timeout_ms": 10000
  }'

Session reuse example

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",
    "session_id": "demo-session-001"
  }'

POST /v1/agent/browse

AI agent-friendly endpoint. Returns clean text, markdown, or html instead of raw page source.

Additional Parameters

NameTypeDefaultDescription
extractstringtexttext / markdown / html / json / pruned
selectorstring-CSS selector to extract specific section
readabilitybooltrueApply Readability to extract main content. Set false for full-page or JavaScript-heavy output
auto_linksboolfalseExtract all links from the page
full_accessboolfalseForce the browser-rendered path and bypass lightweight/cache retrieval
wait_selectorstring-CSS selector to wait for using the full-access extraction path
wait_timeout_msint10000Selector timeout (1,000 - 30,000 ms)

Credit behavior for /v1/agent/browse

/v1/agent/browse returns cleaned text, markdown, HTML, or structured output. When full_access: true or wait_selector is provided, the request uses the full-access path so the page can render before extraction. A successful full-access request costs 10 credits. Without these controls, the API may complete with lightweight extraction for 1 credit. Browse cache hits cost 1 credit for API users; explicit full_access: true bypasses browse cache. If the API automatically promotes a lightweight attempt to full access, the response includes timing.auto_promoted: true.

Result pathCost
Browse cache hit1 credit
Lightweight extraction success1 credit
Full-access extraction success10 credits
extract: "json" structured extraction add-on+5 credits when structured extraction succeeds
Failed request0 credits

Client Timeout Recommendations

Use a 60+ second client timeout for browse, crawl, fetch requests that wait for rendered content, and structured extraction that may render a page. Keep the client timeout at 30 seconds or higher. Very short client cancellation may happen after server-side work has begun, so prefer cancelling before sending the request when an interactive UI has a shorter budget.

Recommended Payloads

The examples below show JSON bodies. Remove comments before sending them as a curl -d payload.

// Portal or search pages
{
  "url": "https://www.example.com",
  "extract": "markdown",
  "readability": false,
  "wait_selector": "body",
  "auto_links": true
}

// SPA docs or GitHub-style pages
{
  "url": "https://docs.example.com",
  "extract": "markdown",
  "full_access": true,
  "readability": false,
  "wait_timeout_ms": 15000,
  "auto_links": true
}

// Static articles, Reddit, HN, or forum threads
{
  "url": "https://news.ycombinator.com",
  "extract": "markdown",
  "readability": true,
  "wait_timeout_ms": 12000
}

Runnable browse example

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": false,
    "wait_selector": "body",
    "auto_links": true
  }'

Response

{
  "success": true,
  "url": "https://news.ycombinator.com",
  "content": "# Hacker News\n\n1. Show HN: ...",
  "content_len": 4521,
  "extract_mode": "markdown",
  "links": ["https://example.com/article1", "..."],
  "timing": { "total_ms": 251, "cache_hit": true },
  "cost_credits": 1
}

Structured JSON Extraction

extract: "json" on /v1/agent/browse is the only mode that performs model-assisted structured extraction. Use markdown, text, html, or /v1/fetch when you only need content retrieval without structured output.

For structured extraction, the service builds an extraction request from the fetched page text's first 8,000 characters, your json_prompt instructions, and your json_schema when provided. Karon API keys, request bearer values, and authentication headers are not included in the extraction prompt.

If structured output cannot be produced, structured_data may be null, or the API may return a generalized error. Raw provider errors are not exposed in public responses.

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/product",
    "extract": "json",
    "json_prompt": "Extract the product name and price.",
    "json_schema": {
      "type": "object",
      "properties": {
        "name": { "type": "string" },
        "price": { "type": "string" }
      }
    }
  }'

POST /v1/solver

Solver-compatible endpoint for tools that accept a provider URL using the common request.get / request.post command shape. Change the provider URL in your tool settings and keep the standard request body shape.

{
  "cmd": "request.get",
  "url": "https://example.com",
  "maxTimeout": 60000
}

Supported commands: request.get, request.post

GET /v1/credits

Check remaining credits and tier info.

curl -sS "https://api.karonlabs.net/v1/credits" \
  -H "Authorization: Bearer __YOUR_API_KEY__"
{
  "name": "example-account",
  "credits_remaining": 850,
  "tier": "free",
  "tier_name": "Free",
  "credits_included": 5000,
  "rate_limit": 300
}

GET /v1/pricing

Public endpoint. No authentication required. Returns current pricing info.

GET /health

Health check. Returns basic service status.

{
  "status": "ok",
  "version": "0.1.0"
}

MCP MCP Clients

Karon MCP exposes the Karon API as native tools inside MCP-compatible agents. The MCP extract tool maps to POST /v1/agent/browse. REST remains the canonical contract.

Claude Code Cursor Codex Any MCP host

How MCP maps to REST

MCP toolREST endpointNotes
extractPOST /v1/agent/browse (extract: "json")Structured extraction add-on (+5 credits on success)
browsePOST /v1/agent/browseCleaned text / markdown / html
fetchPOST /v1/fetchRaw HTML retrieval

Canonical endpoint: POST /v1/agent/browse. Supported public version for explicit full-access extract controls: karon-mcp 1.5.1.

Install

uvx --refresh karon-mcp@1.5.1

Set the API key in your MCP client environment:

KARON_API_KEY=__YOUR_API_KEY__

extract: "json" — success criterion

For structured extraction, success is determined by structured_data, not content_len. In JSON mode, content_len: 0 can be normal — the API ships the structured payload, not the source text.

FieldMeaning
structured_dataPopulated object → success. null → extraction failed.
content_lenMay be 0 in JSON mode. Do not treat as failure.
warningHint about why structured extraction was skipped or rejected.

MCP extract example

{
  "url": "https://quotes.toscrape.com/",
  "json_schema": {
    "first_quote": "string",
    "first_author": "string"
  },
  "readability": true
}

Forcing the full-access path

MCP extract tries the lightweight HTML fetch path first. When that path satisfies the request, the response is produced without going through the full-access path, so the cost reflects the lightweight tier (1 credit) and no full-access work is performed. To require the full-access path explicitly, set full_access: true. Use wait_selector when a specific element must render before extraction.

{
  "url": "https://www.reddit.com/r/programming/",
  "full_access": true,
  "readability": false,
  "json_schema": {
    "top_post_title": "string",
    "top_post_upvotes": "string",
    "top_post_comments": "string"
  }
}

The same contract is available directly over REST:

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://docs.example.com",
    "extract": "json",
    "full_access": true,
    "json_schema": { "title": "string" }
  }'

Troubleshooting

SymptomWhat it meansWhat to do
structured_data: nullStructured extraction failed for this pageCheck the warning field. Tighten json_schema, toggle readability.
content_len: 0 (JSON mode)Normal — payload ships in structured_dataRead structured_data. Treat as success.
cost_credits is 1, not 10Lightweight HTML fetch path satisfied the request without going through the full-access pathIf the full-access path is required, set full_access: true or provide wait_selector.
timing.auto_promoted: trueThe API promoted a lightweight attempt to the full-access path for this requestSet full_access: true for explicit control, or inspect timing.full_access and timing.auto_promoted for billing/debugging.
Client timed out before the responseThe client cancellation may have happened after server-side work had already startedUse a 60+ second timeout for rendered browse/extract calls, and avoid timeouts below 30 seconds.
Old behavior after upgradeMCP host still running a previous karon-mcp processuvx --refresh karon-mcp@1.5.1, then restart the MCP client.

Response examples

Success in JSON mode — content_len: 0 is expected, the payload lives in structured_data:

{
  "success": true,
  "url": "https://quotes.toscrape.com/",
  "content": "",
  "content_len": 0,
  "extract_mode": "json",
  "warning": null,
  "structured_data": {
    "first_quote": "The world as we have created it is a process of our thinking.",
    "first_author": "Albert Einstein"
  },
  "timing": { "total_ms": 612, "cache_hit": false },
  "cost_credits": 6
}

Failure case — structured_data is null, read warning for the cause:

{
  "success": true,
  "url": "https://example.com/dynamic",
  "content": "",
  "content_len": 0,
  "extract_mode": "json",
  "warning": "json_extraction_failed",
  "structured_data": null,
  "timing": { "total_ms": 4185, "cache_hit": false },
  "cost_credits": 1
}
Canonical success rule — for any MCP extract response, success is structured_data != null. content_len is informational only in JSON mode.

Access Behavior

Leave access handling unset for the managed default. The service balances latency and compatibility automatically, while existing clients that already send legacy access options continue to be handled for compatibility.

BehaviorDescriptionTypical latencyBest for
Managed defaultBalances speed and compatibility automaticallyVaries by targetMost integrations
Cached accessReuses established state for repeat requests when available50 - 250msRepeated reads from the same target
Full accessAllows JavaScript-heavy pages to render before capture or extraction3 - 10sPages that need rendering time

Error Codes

StatusErrorDescription
400bad_requestInvalid URL or parameters
400domain_blockedBlocked domain (see AUP)
401unauthorizedMissing or invalid API key
403suspendedAPI key suspended
413payload_too_largeResponse exceeds 10MB
422validation_errorRequest body failed validation
429rate_limit_exceededToo many requests per minute
429daily_limit_exceededDaily request quota reached (free: 10,000/day)
429concurrent_limitToo many concurrent requests — retry shortly
429insufficient_creditsNo credits remaining — contact ceo@karonlabs.net for more
500access_failedThe access attempt could not be completed
502bad_gatewayUpstream connection failed
504gateway_timeoutRequest timed out before completion

Error response format

Errors use a stable JSON shape. Use the type and status fields for programmatic handling. detail is a stable, generalized user-facing message. Upstream state, infrastructure details, and raw exception text are not exposed through this field.

{
  "type": "unauthorized",
  "title": "Unauthorized",
  "status": 401,
  "detail": "authentication required"
}

Failure example

curl -sS -i -X POST "https://api.karonlabs.net/v1/fetch" \
  -H "Authorization: Bearer __YOUR_API_KEY__" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "not-a-url"
  }'
{
  "type": "validation_error",
  "title": "Invalid Request",
  "status": 422,
  "detail": "invalid request parameters"
}

Rate Limits

Rate limits are per API key. Exceeding any limit returns HTTP 429.

TierPer MinutePer DayConcurrent Requests
Free (beta)300/min10,000/dayTier-limited

Concurrent Requests — concurrent request limits apply per tier and may return HTTP 429 when the account has too many active requests. Cached responses are not affected by this limit. If you receive 429, wait briefly and retry with backoff.

Free during beta · Paid tiers coming Q3 2026 · Need more? Contact ceo@karonlabs.net

Restricted Domains

Requests to the following domains are blocked and return HTTP 400 with type: "domain_blocked". This policy protects against abuse and aligns with industry-standard acceptable use practices.

CategoryDomainsReason
Ticket platformsticketmaster.com, eventbrite.com, stubhub.com, axs.comAutomated ticket purchasing is prohibited
Email servicesoutlook.com, outlook.live.com, yahoo.com, mail.yahoo.comLogin-gated data / account access
Financialpaypal.com, chase.com, bankofamerica.com, wellsfargo.com, binance.com, coinbase.comFinancial service abuse prevention
Streamingnetflix.com, disneyplus.com, spotify.com, twitch.tvLogin-gated content
Gamingsteampowered.com, playstation.comLogin-gated / purchase automation
Classifiedscraigslist.org, craigslist.comAutomated posting / spam prevention
Social (login)linkedin.comLogin-gated profile data

Subdomains are automatically included (e.g., blocking paypal.com also blocks www.paypal.com). This list may be updated without notice. If your legitimate use case requires access to a restricted domain, contact ceo@karonlabs.net.

Tips

First request can be slower (3-10s) because the service establishes an access session on the first visit. Subsequent requests can reuse cached state and complete faster.
Use wait_selector for JavaScript-heavy SPAs that need time to render content.
Use extract: "markdown" in /v1/agent/browse for the cleanest LLM-ready output.
Prefer the managed default for new integrations. Add wait_selector only when the target page needs time to render before capture.