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
| Name | Type | Default | Description |
|---|---|---|---|
| url | string REQUIRED | - | Target URL (max 8,192 chars) |
| wait_selector | string | - | CSS selector used if the request needs full-access fallback before capturing |
| wait_timeout_ms | int | 10000 | Selector timeout (1,000 - 30,000 ms) |
| session_id | string | - | 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" }
}
"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 path | Cost |
|---|---|
| Response cache hit | 1 credit |
| Lightweight HTML fetch success | 1 credit |
| Full-access fallback success | 10 credits |
| Failed request | 0 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
| Name | Type | Default | Description |
|---|---|---|---|
| extract | string | text | text / markdown / html / json / pruned |
| selector | string | - | CSS selector to extract specific section |
| readability | bool | true | Apply Readability to extract main content. Set false for full-page or JavaScript-heavy output |
| auto_links | bool | false | Extract all links from the page |
| full_access | bool | false | Force the browser-rendered path and bypass lightweight/cache retrieval |
| wait_selector | string | - | CSS selector to wait for using the full-access extraction path |
| wait_timeout_ms | int | 10000 | Selector 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 path | Cost |
|---|---|
| Browse cache hit | 1 credit |
| Lightweight extraction success | 1 credit |
| Full-access extraction success | 10 credits |
extract: "json" structured extraction add-on | +5 credits when structured extraction succeeds |
| Failed request | 0 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.
How MCP maps to REST
| MCP tool | REST endpoint | Notes |
|---|---|---|
| extract | POST /v1/agent/browse (extract: "json") | Structured extraction add-on (+5 credits on success) |
| browse | POST /v1/agent/browse | Cleaned text / markdown / html |
| fetch | POST /v1/fetch | Raw 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.
| Field | Meaning |
|---|---|
| structured_data | Populated object → success. null → extraction failed. |
| content_len | May be 0 in JSON mode. Do not treat as failure. |
| warning | Hint 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
| Symptom | What it means | What to do |
|---|---|---|
| structured_data: null | Structured extraction failed for this page | Check the warning field. Tighten json_schema, toggle readability. |
| content_len: 0 (JSON mode) | Normal — payload ships in structured_data | Read structured_data. Treat as success. |
| cost_credits is 1, not 10 | Lightweight HTML fetch path satisfied the request without going through the full-access path | If the full-access path is required, set full_access: true or provide wait_selector. |
| timing.auto_promoted: true | The API promoted a lightweight attempt to the full-access path for this request | Set full_access: true for explicit control, or inspect timing.full_access and timing.auto_promoted for billing/debugging. |
| Client timed out before the response | The client cancellation may have happened after server-side work had already started | Use a 60+ second timeout for rendered browse/extract calls, and avoid timeouts below 30 seconds. |
| Old behavior after upgrade | MCP host still running a previous karon-mcp process | uvx --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
}
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.
| Behavior | Description | Typical latency | Best for |
|---|---|---|---|
| Managed default | Balances speed and compatibility automatically | Varies by target | Most integrations |
| Cached access | Reuses established state for repeat requests when available | 50 - 250ms | Repeated reads from the same target |
| Full access | Allows JavaScript-heavy pages to render before capture or extraction | 3 - 10s | Pages that need rendering time |
Error Codes
| Status | Error | Description |
|---|---|---|
| 400 | bad_request | Invalid URL or parameters |
| 400 | domain_blocked | Blocked domain (see AUP) |
| 401 | unauthorized | Missing or invalid API key |
| 403 | suspended | API key suspended |
| 413 | payload_too_large | Response exceeds 10MB |
| 422 | validation_error | Request body failed validation |
| 429 | rate_limit_exceeded | Too many requests per minute |
| 429 | daily_limit_exceeded | Daily request quota reached (free: 10,000/day) |
| 429 | concurrent_limit | Too many concurrent requests — retry shortly |
| 429 | insufficient_credits | No credits remaining — contact ceo@karonlabs.net for more |
| 500 | access_failed | The access attempt could not be completed |
| 502 | bad_gateway | Upstream connection failed |
| 504 | gateway_timeout | Request 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.
| Tier | Per Minute | Per Day | Concurrent Requests |
|---|---|---|---|
| Free (beta) | 300/min | 10,000/day | Tier-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.
| Category | Domains | Reason |
|---|---|---|
| Ticket platforms | ticketmaster.com, eventbrite.com, stubhub.com, axs.com | Automated ticket purchasing is prohibited |
| Email services | outlook.com, outlook.live.com, yahoo.com, mail.yahoo.com | Login-gated data / account access |
| Financial | paypal.com, chase.com, bankofamerica.com, wellsfargo.com, binance.com, coinbase.com | Financial service abuse prevention |
| Streaming | netflix.com, disneyplus.com, spotify.com, twitch.tv | Login-gated content |
| Gaming | steampowered.com, playstation.com | Login-gated / purchase automation |
| Classifieds | craigslist.org, craigslist.com | Automated posting / spam prevention |
| Social (login) | linkedin.com | Login-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
wait_selector for JavaScript-heavy SPAs that need time to render content.extract: "markdown" in /v1/agent/browse for the cleanest LLM-ready output.wait_selector only when the target page needs time to render before capture.