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 parameter | Required | Description |
|---|---|---|
url | Yes | One absolute http(s) article URL. Remove redirect wrappers and fragments when you can. |
include | No | markdown 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"
]
}'| Field | Type | Required | Description |
|---|---|---|---|
urls | string[] | Yes | 1-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:
| Limit | Applies to | Response when exceeded |
|---|---|---|
| 10 requests per minute per API key | Single and batch lookups, counted together | 429 RATE_LIMITED, retry_after_seconds: 60 |
| 10 in-flight lookups per organization | Every URL being fetched right now | 429 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 status | Code | Meaning | What to do |
|---|---|---|---|
400 | INVALID_REQUEST | Unsupported include value, include on batch, or force_refresh | Use include=markdown on the single route only, and drop force_refresh. |
400 | INVALID_URL | The URL is not an absolute http(s) URL | Send a full URL such as https://example.com/story. |
401 | UNAUTHORIZED | Missing or invalid API key | Check the bearer token. |
402 | INSUFFICIENT_CREDITS | Balance is below 0.1 credit | Purchase credits before retrying. |
403 | FORBIDDEN | Key lacks media_lists:manage | Create or use a key with the required scope. |
429 | RATE_LIMITED | Per-minute, in-flight, or API-wide limit reached | Wait for retry_after_seconds, then retry. |
502 | ARTICLE_FETCH_FAILED | The page could not be fetched or parsed | Check 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.
Automated Media Lists
Create a researched media list with an approval-gated browser link or the fully automated Medialyst REST API.
Medialyst MCP
Connect trusted agents to Medialyst so they can look up articles and publications, poll journalist requests and moves, search news, enrich journalists, and check credit balance.