# STELQ Content API

Clean, structured extraction from any URL — Markdown and/or JSON, not HTML soup. Synchronous: one request, one response.

- **Endpoint:** `POST https://api.stelq.com/v1/content/extract`
- **Auth:** `Authorization: Bearer $STELQ_KEY`
- **Price:** $0.002 / page
- **Mode:** synchronous
- **Canonical URL:** https://stelq.com/api/docs/content (public, no auth, always current)

## Authentication

Every request needs a bearer token: `Authorization: Bearer $STELQ_KEY`. Create and scope keys in the console under API Keys — the secret is shown once. In the in-console Playground the key is injected for you; copied payloads reference the `$STELQ_KEY` environment variable, so set it in your agent's environment instead of pasting a live secret into a prompt.

## Request

`POST /v1/content/extract`

| Field | Type | Required | Notes |
| --- | --- | --- | --- |
| `url` | string | yes | The page to extract. |
| `formats` | string[] | no | Any of markdown, json (default ["markdown"]). |
| `includeMetadata` | boolean | no | Include title, language, byline and fetch time (default false). |
| `max_characters` | integer | no | Maximum returned text (default 50000; 0 returns the complete extraction). |
| `text_query` | string | no | Question or phrase used to preserve relevant excerpts from anywhere in a long page. |
| `text_keywords` | string[] | no | Terms to find across the complete extraction and preserve in the bounded response. |
| `relevant_characters` | integer | no | Space reserved for matching excerpts (default 5000; 500 to 20000). |

```json
{
  "url": "https://example.com/report",
  "formats": [
    "markdown",
    "json"
  ],
  "includeMetadata": true,
  "text_query": "What changed in the revised policy?",
  "text_keywords": [
    "revised policy",
    "effective date"
  ]
}
```

## Response

```json
{
  "url": "https://example.com/report",
  "markdown": "# Report\n\nClean extracted body…",
  "json": {
    "title": "Report",
    "sections": []
  },
  "metadata": {
    "title": "Report",
    "lang": "en",
    "fetchedAt": "2026-06-14T12:00:00Z"
  },
  "text_selection": "head-plus-relevant-excerpts",
  "text_original_characters": 87342,
  "text_truncated": true,
  "text_relevant_characters": 4871
}
```

## Errors

| Status | Meaning |
| --- | --- |
| 400 | Invalid request — a field is missing or malformed (the body says which). |
| 401 | Missing or invalid API key. |
| 402 | Insufficient balance — top up credits to continue. |
| 429 | Rate limited — back off and retry after the Retry-After header. |
| 502 | Upstream temporarily unavailable — safe to retry; not charged. |

## Rate limits

Up to 50 requests/second per key.
