API reference

Forage API

Forage turns any web page or audio file into AI-ready data. Every endpoint is a single HTTPS request that returns markdown, structured JSON, an image, a PDF, or a transcript — whatever an agent or pipeline needs next.

The production domain forageapi.com is coming soon. Until it flips over, the API is live at https://forageapi.com — the examples below use that base URL. Swap in forageapi.com once it's announced.

Quickstart

Two calls and you're done: mint a free key, then convert your first page.

1. Get a free key (300 credits, no card)

shell
curl -X POST https://forageapi.com/v1/keys \
  -H "content-type: application/json" \
  -d '{"email":"you@example.com"}'

The response includes your key. It's shown exactly once — store it now.

201 Created
{
  "key": "fk_live_9f8a1c...e2",
  "key_id": "key_ab12cd34ef56",
  "credits": 300,
  "message": "Store this key now — it is shown exactly once.",
  "docs": "https://forageapi.com/docs"
}

2. Convert a page to markdown

shell
curl -X POST https://forageapi.com/v1/markdown \
  -H "Authorization: Bearer fk_live_9f8a1c...e2" \
  -H "content-type: application/json" \
  -d '{"url":"https://example.com"}'

That's it. Every other endpoint follows the same shape: POST JSON, pass your bearer token, get JSON (or a binary file) back.

Authentication

Pass your key as a bearer token on every request except creating a key and the public GET /health check.

header
Authorization: Bearer fk_live_...

Keys start with fk_live_. Lose yours? There's no recovery — mint a new one (one per email means you'll want a fresh address, or email us to reset). Requests are rate-limited to 60 per minute per key.

Credits & billing

Every call spends credits. Your free key starts with 300; top up in one-time packs with no subscription (see pricing).

EndpointCost
/v1/markdown1 credit
/v1/screenshot1 credit
/v1/pdf2 credits
/v1/extract2 credits
/v1/reviews2 credits (not charged if no reviews found)
/v1/transcribe2 credits minimum, then 1 per started minute
/v1/keys, /v1/usageFree
Honest failure policy. If a call fails — a page won't fetch, a conversion errors, an audio URL is unreachable — the credits are refunded automatically. You only pay for data you actually receive.

Errors

Errors return a JSON body with an error code (and usually a message) alongside the HTTP status.

StatusCodeMeaning
400missing_url / missing_schema / invalid_emailThe request body is missing a required field or is malformed.
401missing_api_key / invalid_api_keyNo bearer token, or the key is unknown or disabled.
402insufficient_creditsNot enough credits. Response includes a buy link.
409email_existsA free key was already issued for that email.
422audio_too_largeAudio exceeds the 24MB limit for transcription.
429rate_limitedOver 60 requests/minute per key (or too many signups per IP).
502fetch_failed / conversion_failed / capture_failedAn upstream fetch or conversion failed. Auto-refunded.
402 Payment Required
{
  "error": "insufficient_credits",
  "buy": "https://forageapi.com/#pricing"
}

Create a key

POST/v1/keysFree · no auth

Mint a free API key seeded with 300 credits. One key per email address; the secret is returned once and never again.

Request body

  • email (string, required) — a valid email address.
shell
curl -X POST https://forageapi.com/v1/keys \
  -H "content-type: application/json" \
  -d '{"email":"you@example.com"}'

Response · 201

application/json
{
  "key": "fk_live_9f8a1c...e2",
  "key_id": "key_ab12cd34ef56",
  "credits": 300,
  "message": "Store this key now — it is shown exactly once.",
  "docs": "https://forageapi.com/docs"
}

Errors: 400 invalid_email, 409 email_exists, 429 rate_limited.

Markdown

POST/v1/markdown1 credit

Fetch a page and return clean, LLM-ready markdown with boilerplate removed.

Request body

  • url (string, required) — the page to convert.
  • render (string, optional)"auto" (default), "never", or "always". Controls headless-browser rendering.
shell
curl -X POST https://forageapi.com/v1/markdown \
  -H "Authorization: Bearer fk_live_..." \
  -H "content-type: application/json" \
  -d '{"url":"https://example.com","render":"auto"}'

Response · 200

application/json
{
  "url": "https://example.com",
  "rendered": false,
  "markdown": "# Example Domain\n\nThis domain is for use in...",
  "tokens_estimate": 42
}

rendered tells you whether a headless browser was used. tokens_estimate is a rough token count for budgeting.

Screenshot

POST/v1/screenshot1 credit

Capture a PNG of a page rendered in a real headless browser. Returns the raw image with content-type: image/png.

Request body

  • url (string, required).
  • full_page (boolean, default false) — capture the entire scrollable page.
  • width (integer, default 1280) · height (integer, default 800) — viewport, clamped 320–2560.
  • wait_ms (integer, default 0) — extra wait after load, up to 5000ms.
shell
curl -X POST https://forageapi.com/v1/screenshot \
  -H "Authorization: Bearer fk_live_..." \
  -H "content-type: application/json" \
  -d '{"url":"https://example.com","full_page":true}' \
  --output screenshot.png

Response · 200

Binary PNG data (image/png). Pipe it to a file with --output as above.

PDF

POST/v1/pdf2 credits

Render a live page to a print-ready A4 PDF with backgrounds. Returns application/pdf.

Request body

  • url (string, required).
  • width · height (integer, optional) — viewport for layout.
  • wait_ms (integer, optional) — extra wait after load, up to 5000ms.
shell
curl -X POST https://forageapi.com/v1/pdf \
  -H "Authorization: Bearer fk_live_..." \
  -H "content-type: application/json" \
  -d '{"url":"https://example.com"}' \
  --output page.pdf

Response · 200

Binary PDF data (application/pdf).

Extract

POST/v1/extract2 credits

Pull structured JSON from a page (or raw HTML) that matches a JSON Schema you supply. Forage never invents data — fields not present in the content come back null.

Request body

  • url (string) or html (string) — one is required.
  • schema (object, required) — a JSON Schema describing the output you want.
  • instructions (string, optional) — extra guidance for the extractor.
  • render (string, optional)"auto" / "never" / "always".
shell
curl -X POST https://forageapi.com/v1/extract \
  -H "Authorization: Bearer fk_live_..." \
  -H "content-type: application/json" \
  -d '{
    "url": "https://example.com/product/42",
    "schema": {
      "type": "object",
      "properties": {
        "title": { "type": "string" },
        "price": { "type": "number" },
        "in_stock": { "type": "boolean" }
      }
    }
  }'

Response · 200

application/json
{
  "url": "https://example.com/product/42",
  "rendered": false,
  "data": {
    "title": "Foraging Basket, Wax Canvas",
    "price": 48.0,
    "in_stock": true
  }
}

Errors: 400 missing_input (no url or html), 400 missing_schema.

Transcribe

POST/v1/transcribe2 credits + 1 / min

Transcribe an audio file with Whisper, returning full text plus timestamped segments and a VTT track. Charged 2 credits minimum, then 1 credit per started minute of audio. Maximum file size is 24MB.

Request body

  • url (string, required) — a direct link to an audio file.
shell
curl -X POST https://forageapi.com/v1/transcribe \
  -H "Authorization: Bearer fk_live_..." \
  -H "content-type: application/json" \
  -d '{"url":"https://example.com/episode.mp3"}'

Response · 200

application/json
{
  "url": "https://example.com/episode.mp3",
  "duration_seconds": 184.2,
  "credits_charged": 4,
  "text": "Welcome back to the show. Today we're...",
  "segments": [
    { "start": 0.0, "end": 4.8, "text": "Welcome back to the show." },
    { "start": 4.8, "end": 9.1, "text": "Today we're talking about..." }
  ],
  "vtt": "WEBVTT\n\n00:00.000 --> 00:04.800\nWelcome back..."
}

Errors: 422 audio_too_large (over 24MB), 502 fetch_failed (audio URL unreachable — auto-refunded).

Reviews

POST/v1/reviews2 credits

Extract schema.org Review and AggregateRating data from any page carrying JSON-LD markup (many product, store, and Trustpilot-style pages). If the page has no review markup, you are not charged.

Request body

  • url (string, required).
  • render (string, optional)"auto" / "never" / "always".
shell
curl -X POST https://forageapi.com/v1/reviews \
  -H "Authorization: Bearer fk_live_..." \
  -H "content-type: application/json" \
  -d '{"url":"https://example.com/product/42"}'

Response · 200 (reviews found)

application/json
{
  "url": "https://example.com/product/42",
  "rendered": false,
  "subject": "Foraging Basket, Wax Canvas",
  "aggregate": { "rating": 4.6, "count": 128 },
  "count": 2,
  "reviews": [
    {
      "author": "Dana R.",
      "rating": 5,
      "date": "2026-05-11",
      "title": "Holds up in the rain",
      "body": "Took it out mushroom hunting all season..."
    },
    {
      "author": "Sam T.",
      "rating": 4,
      "date": "2026-04-02",
      "title": "Roomy",
      "body": "Wish the strap were a touch longer."
    }
  ]
}

Response · 200 (none found — not charged)

application/json
{
  "url": "https://example.com/plain-page",
  "rendered": false,
  "reviews": [],
  "aggregate": null,
  "message": "No schema.org review markup found on this page. You were not charged."
}

Usage

GET/v1/usageFree

Check your current balance and the 50 most recent usage events for your key.

shell
curl https://forageapi.com/v1/usage \
  -H "Authorization: Bearer fk_live_..."

Response · 200

application/json
{
  "key_id": "key_ab12cd34ef56",
  "balance": 294,
  "recent": [
    { "endpoint": "markdown", "credits": 1, "created_at": "2026-07-02T18:20:11Z" },
    { "endpoint": "extract",  "credits": 2, "created_at": "2026-07-02T18:19:47Z" }
  ]
}
Prefer to generate a client? Grab the OpenAPI 3.1 spec, or point an AI agent at llms.txt. Questions: willchilcutt@gmail.com.