Developers

REST API Reference

Use these entry points to work with the Medialyst API.

1. Get An API Key

Create API keys from the Medialyst Developers page. The _ segment resolves to your current organization.

Give each key a clear name, choose the smallest useful scopes, copy the raw key immediately, and store it in secret storage or an environment variable such as MEDIALYST_API_KEY.

Send the key as a bearer token on API requests:

Authorization: Bearer <YOUR_API_KEY>

Keep keys private

Medialyst only shows the raw API key once. Do not paste keys into prompts, commit them to source control, or share screenshots that reveal them.

2. Poll Journalist Moves

GET /api/v1/journalist-moves returns de-duplicated journalist outlet-move records observed after an explicit timestamp or opaque cursor. It requires an active Scale-plan credential and costs zero credits. since filters on when Medialyst observed each move — not the move's effective date — so a poller still receives late-reported moves. Each move also carries a nullable published_at (the source's own publication time) for consumers that want recently-announced rather than recently-observed moves.

Follow the Journalist Moves API guide for the response schema, the exclusive UTC cursor semantics, the de-duplication rule, the match-state default, and a complete daily polling example.

3. Automated Media Lists

Follow the Automated Media Lists guide to choose between an approval-gated browser deep link and a fully automated API job. The guide covers creating a researched journalist list, polling its background job, retrieving normalized results, and finding API-created lists in the Medialyst app.

target_list_size on POST /api/v1/media-lists:create-async is the most credits the list may consume (1 to 1,000; the ceiling on paid plans), not a row count. Each row that delivers a verified, deliverable email costs 1 credit; blank rows cost nothing and do not count against the budget. A journalist with several matching articles appears once per article, and each billable row costs a credit. The initial search is bounded by the target, then the Beat Sweep keeps adding rows until the budget is spent or the angles run dry, so result.total_rows can exceed target_list_size; the job's budget object reports the cap, what has billed, and what rows still enriching hold. Rule of thumb: ask for roughly twice the named journalists you want.

4. Enrich Journalists

POST /api/v1/journalists/enrich accepts known journalist references as well as article URLs. The canonical reference request is:

{
    "from": [
        {
            "type": "journalist_reference",
            "name": "Jane Doe",
            "publication": "The Daily Example"
        }
    ]
}

For every journalist_reference, name requires at least one of publication, domain, or url. Use article_url with a real article URL when you want to enrich that article's author; both source types can be mixed in the same from array.

Enrichment is asynchronous. The create request returns a durable job id immediately. Poll GET /api/v1/journalist-enrichment-jobs/{jobId} until its status is complete or failed. The deprecated create-call fields options.wait and options.timeout_ms do not change this workflow.

This API uses outcome billing. It charges 1 credit for each source that returns a journalist with a verified, deliverable email and 0 credits for a source with no verified-email result. Misses are free — there is no upfront charge and no refund step.

5. Look Up Articles

GET /api/v1/articles/lookup returns canonical metadata — title, publish date, author name and profile, site name, language, excerpt, and word count — for one article URL. POST /api/v1/articles/lookup:batch does the same for 1-10 URLs. Add include=markdown to the single lookup when you need the extracted body; it is the only accepted include value, and batch lookup does not accept include at all. Author details are part of the default response. Each successful URL costs 0.1 credit; per-URL failures cost 0 credits.

Follow the Article Lookup API guide for parameters, response shapes, error codes, and the lookup-specific rate limits.

6. Rate Limits

Limits are enforced per API key over a one-minute window unless noted. There is no daily request cap: credits, not requests, are the consumable, so a key can keep calling the API as long as it stays inside the per-minute and active-job limits below.

ScopeLimitResponse when exceeded
All /api/v1 routes60 requests per minute429 RATE_LIMITED, retry_after_seconds: 60
GET /api/v1/articles/lookup and POST /api/v1/articles/lookup:batch10 requests per minute (both routes counted together), plus 10 in-flight lookups per organization429 RATE_LIMITED, retry_after_seconds: 60 (per minute) or 1 (in flight)
GET /api/v1/publications/lookup and POST /api/v1/publications/lookup:batch60 requests per minute; force_refresh lookups 5 per 15 minutes429 RATE_LIMITED, retry_after_seconds: 60 or 900
POST /api/v1/journalists/enrich10 active (pending or processing) jobs per key429 RATE_LIMITED, retry_after_seconds: 5
POST /api/v1/media-lists:create-async3 active (pending or processing) jobs per key; jobs complete on their own and deleting a list frees its slot429 RATE_LIMITED
GET /api/v1/journalist-moves30 polls per minute429 RATE_LIMITED; see Journalist Moves errors

Every 429 body has code: "RATE_LIMITED" and, where a wait is meaningful, retry_after_seconds; the same value is sent as a Retry-After header. Hosted MCP tools call these routes, so they share the same limits.

Handling 429

  • Read retry_after_seconds from the body (or the Retry-After header), wait at least that long, then retry. Rejected requests still count toward the 60-per-minute window, so a tight retry loop only extends the wait.
  • Prefer batch routes for bursts: one lookup:batch call with 10 URLs is one request, while 10 single lookups use the whole article-lookup allowance.
  • For journalist enrichment and async media lists, a 429 means the active-job cap, not request rate. Poll the existing jobs until they are complete or failed before submitting more.
  • If an agent reports a "daily limit" on API calls, it has misread one of the limits above — the REST API has no daily limit. Wait retry_after_seconds and continue. The in-app chat does have a separate daily message cap; see the FAQ.

7. API Documentation

Browse the interactive API documentation at /api/docs.

8. Agent-Readable OpenAPI Reference

Use the raw OpenAPI document at /api/open-api.