Developers

Article Lookup API

GET /api/v1/articles/lookup returns canonical metadata for one article URL. POST /api/v1/articles/lookup:batch returns the same metadata for 1-10 URLs in one call. Both perform a live fetch, so they work for any public article, not only articles Medialyst has already seen.

Author details — name, profile URL, and any social links found on the page — are part of the default response. You do not need an include value to get them.

Before You Start

Create an API key from the Medialyst Developers page with the media_lists:manage scope, store it in secret storage or an environment variable such as MEDIALYST_API_KEY, and send it as a bearer token:

Authorization: Bearer <YOUR_API_KEY>

All examples below use https://medialyst.ai/api as the API base URL.

Single Lookup

curl --request GET \
  'https://medialyst.ai/api/v1/articles/lookup?url=https%3A%2F%2Fexample.com%2Fstory' \
  --header "Authorization: Bearer $MEDIALYST_API_KEY"
Query parameterRequiredDescription
urlYesOne absolute http(s) article URL. Remove redirect wrappers and fragments when you can.
includeNomarkdown is the only accepted value. Omit it for metadata-only lookup.

The response carries one result:

{
    "request_id": "req_01HT...",
    "result": {
        "url": "https://example.com/story",
        "status": "ok",
        "served_from": "live",
        "title": "Example Story",
        "published_at": "2026-08-14T09:30:00.000Z",
        "author": {
            "name": "Jane Doe",
            "profile_url": "https://example.com/authors/jane-doe",
            "social": {
                "twitter": ["https://x.com/janedoe"]
            }
        },
        "site_name": "Example",
        "language": "en",
        "excerpt": "The first paragraph of the story...",
        "word_count": 850,
        "extraction_strategy": "scrapingbee_ai",
        "extracted_at": "2026-08-14T10:00:00.000Z"
    }
}

title, published_at, author.name, author.profile_url, site_name, language, excerpt, and word_count are null when the page does not expose them. author.social is present only when the page links at least one social profile.

Include Markdown

Add include=markdown when you need the extracted article body:

curl --request GET \
  'https://medialyst.ai/api/v1/articles/lookup?url=https%3A%2F%2Fexample.com%2Fstory&include=markdown' \
  --header "Authorization: Bearer $MEDIALYST_API_KEY"

The result gains a markdown field. It is null when extraction produced no usable body; keep using the returned metadata rather than inventing article text.

markdown is the only accepted include value. Any other value — including a comma-separated list that mixes markdown with something else — returns 400 INVALID_REQUEST with the message Unsupported include value. Use include=markdown or omit include. The endpoint also rejects force_refresh with 400 INVALID_REQUEST, because every lookup is already live.

Batch Lookup

curl --request POST \
  'https://medialyst.ai/api/v1/articles/lookup:batch' \
  --header "Authorization: Bearer $MEDIALYST_API_KEY" \
  --header 'Content-Type: application/json' \
  --data '{
    "urls": [
      "https://example.com/story-one",
      "https://example.org/story-two"
    ]
  }'
FieldTypeRequiredDescription
urlsstring[]Yes1-10 absolute http(s) article URLs. Split larger sets into multiple calls.

Batch lookup does not accept include. Sending ?include=markdown on the batch route returns 400 INVALID_REQUEST; use the single lookup for the one URL whose body you need. The request body is strict — unknown fields are rejected.

The response returns one entry per submitted URL, in input order. A failing URL never fails the whole request: it appears with status: "error" and the same code and status a single lookup would have returned.

{
    "request_id": "req_01HT...",
    "results": [
        {
            "url": "https://example.com/story-one",
            "status": "ok",
            "served_from": "live",
            "title": "Story One",
            "published_at": "2026-08-14T09:30:00.000Z",
            "author": { "name": "Jane Doe", "profile_url": null },
            "site_name": "Example",
            "language": "en",
            "excerpt": "The first paragraph...",
            "word_count": 640,
            "extraction_strategy": "scrapingbee_ai",
            "extracted_at": "2026-08-14T10:00:00.000Z"
        },
        {
            "url": "https://example.org/story-two",
            "status": "error",
            "error": {
                "code": "ARTICLE_FETCH_FAILED",
                "message": "Article lookup failed. Adjust the URL or retry the request.",
                "status": 502
            }
        }
    ]
}

Credits

Article lookup costs 0.1 credit per successful URL, on both routes. Per-URL failures cost 0 credits, so a batch budget depends on how many URLs succeed rather than how many you submit. A lookup that cannot be paid for returns 402 INSUFFICIENT_CREDITS with the required and available amounts in details.

Rate Limits

Article lookup has its own limits on top of the API-wide 60 requests per minute:

LimitApplies toResponse when exceeded
10 requests per minute per API keySingle and batch lookups, counted together429 RATE_LIMITED, retry_after_seconds: 60
10 in-flight lookups per organizationEvery URL being fetched right now429 RATE_LIMITED, retry_after_seconds: 1

A batch call counts as one request against the per-minute limit, so ten URLs in one lookup:batch call use one-tenth of the allowance that ten single lookups would. Each URL in a batch does occupy its own in-flight slot; when a URL cannot get a slot it comes back as a per-URL RATE_LIMITED error inside results, and you only need to retry those URLs.

Every 429 sets a Retry-After header and a retry_after_seconds value. Wait at least that long before retrying. There is no daily cap on article lookups or on the API as a whole.

Common Errors

HTTP statusCodeMeaningWhat to do
400INVALID_REQUESTUnsupported include value, include on batch, or force_refreshUse include=markdown on the single route only, and drop force_refresh.
400INVALID_URLThe URL is not an absolute http(s) URLSend a full URL such as https://example.com/story.
401UNAUTHORIZEDMissing or invalid API keyCheck the bearer token.
402INSUFFICIENT_CREDITSBalance is below 0.1 creditPurchase credits before retrying.
403FORBIDDENKey lacks media_lists:manageCreate or use a key with the required scope.
429RATE_LIMITEDPer-minute, in-flight, or API-wide limit reachedWait for retry_after_seconds, then retry.
502ARTICLE_FETCH_FAILEDThe page could not be fetched or parsedCheck the URL resolves publicly; retry once after a short delay.

MCP

The hosted Medialyst MCP server exposes these routes as lookup_article (with an include_markdown boolean instead of the include query parameter) and lookup_articles. Auth, scopes, credits, rate limits, and errors match direct API calls.