{"openapi":"3.1.0","info":{"title":"Medialyst.ai API","description":"Development documentation","version":"1.0.0"},"servers":[{"url":"https://medialyst.ai","description":"API server"}],"paths":{"/api/health":{"get":{"responses":{"200":{"description":"OK"}},"operationId":"getApiHealth","tags":["Health"],"parameters":[],"summary":"Health check","description":"Returns 200 if the server is healthy"}},"/api/v1/media-lists/{mediaListId}":{"get":{"responses":{"200":{"description":"Media-list metadata, columns, and optional row values","content":{"application/json":{"schema":{"type":"object","properties":{"media_list":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"description":{"type":["string","null"]},"status":{"type":"string"},"columns":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"workflowType":{"type":"string"},"dependencies":{"type":"array","items":{"type":"string"}}},"required":["id","name","workflowType"],"additionalProperties":true}},"schema_omitted":{"type":"boolean"},"settings":{"type":"object","additionalProperties":{}},"row_count":{"type":"integer","minimum":0},"created_at":{"type":["string","null"],"format":"date-time"},"updated_at":{"type":["string","null"],"format":"date-time"}},"required":["id","name","description","status","columns","schema_omitted","settings","row_count","created_at","updated_at"]},"rows":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"position":{"type":"integer"},"values":{"type":"object","additionalProperties":{}},"data":{"type":"object","additionalProperties":{}},"origin":{"type":["object","null"],"additionalProperties":{}},"createdAt":{"type":["string","null"],"format":"date-time"},"updatedAt":{"type":["string","null"],"format":"date-time"}},"required":["id","position","values"]}},"page":{"type":"object","properties":{"next_cursor":{"type":["integer","null"],"minimum":0}},"required":["next_cursor"]}},"required":["media_list","rows","page"]}}}},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient scope"},"404":{"description":"Media list not found"}},"operationId":"getApiV1Media-listsByMediaListId","tags":["Media Lists"],"parameters":[{"in":"query","name":"include_rows","schema":{"type":"boolean","default":false}},{"in":"query","name":"include_schema","schema":{"type":"boolean","default":false}},{"in":"query","name":"row_detail","schema":{"type":"string","enum":["preview","full"],"default":"preview"}},{"in":"query","name":"limit","schema":{"type":"integer","minimum":1,"maximum":100,"default":25}},{"in":"query","name":"cursor","schema":{"type":"integer","minimum":0,"default":0}},{"schema":{"type":"string"},"in":"path","name":"mediaListId","required":true}],"summary":"Get a media list","description":"Read the organization-scoped media-list table. For website-equivalent completed rows, use include_rows=true, row_detail=full, and paginate with page.next_cursor. The response maps every returned column id to its row value and restores contact values persisted before contact masking was removed. include_schema=false (the default) returns safe column identity/type metadata without execution configuration."}},"/api/v1/projects":{"get":{"responses":{"200":{"description":"Projects in the authenticated organization"},"400":{"description":"Invalid request, or an attempt to delete the Default project, which cannot be deleted"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient scope or plan upgrade required"},"404":{"description":"Project or file not found"},"409":{"description":"Version or resource conflict"},"429":{"description":"Rate limited"}},"operationId":"getApiV1Projects","tags":["Projects"],"parameters":[],"summary":"List projects","description":"List active projects with file, media-list, and memory counts. The default project uses the stable id general and is flagged with isDefault; it can be renamed but not archived or deleted."},"post":{"responses":{"201":{"description":"Project created"},"400":{"description":"Invalid request, or an attempt to delete the Default project, which cannot be deleted"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient scope or plan upgrade required"},"404":{"description":"Project or file not found"},"409":{"description":"Version or resource conflict"},"429":{"description":"Rate limited"}},"operationId":"postApiV1Projects","tags":["Projects"],"parameters":[],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":120},"description":{"type":["string","null"],"maxLength":2000}},"required":["name"]}}}},"summary":"Create a project"}},"/api/v1/projects/{projectId}/files:upload-text":{"post":{"responses":{"201":{"description":"Text file stored and extraction started"},"400":{"description":"Invalid request, or an attempt to delete the Default project, which cannot be deleted"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient scope or plan upgrade required"},"404":{"description":"Project or file not found"},"409":{"description":"Version or resource conflict"},"429":{"description":"Rate limited"}},"operationId":"postApiV1ProjectsByProjectIdFiles:upload-text","tags":["Projects"],"parameters":[{"schema":{"type":"string"},"in":"path","name":"projectId","required":true}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"title":{"type":"string","minLength":1,"maxLength":200},"content":{"type":"string","minLength":1},"mimeType":{"type":"string","enum":["text/markdown","text/plain"]},"clientUploadKey":{"type":"string","minLength":1,"maxLength":64}},"required":["title","content"],"additionalProperties":false}}}},"summary":"Upload a text project file in one call","description":"Upload UTF-8 Markdown or plain text up to 4 MB. A title without a known project-file extension gets .md or .txt from mimeType, even when the human-readable title contains a dot; when mimeType is omitted, .txt selects text/plain, .md/.markdown selects text/markdown, and other titles default to Markdown. Medialyst stores the bytes, marks the file extracting, and starts safe extraction; poll the file endpoint until ready or failed. Send a clientUploadKey and reuse it on retries so a lost response cannot create a duplicate file."}},"/api/v1/projects/{projectId}/memory":{"get":{"responses":{"200":{"description":"Current Markdown memory document"},"400":{"description":"Invalid request, or an attempt to delete the Default project, which cannot be deleted"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient scope or plan upgrade required"},"404":{"description":"Project or file not found"},"409":{"description":"Version or resource conflict"},"429":{"description":"Rate limited"}},"operationId":"getApiV1ProjectsByProjectIdMemory","tags":["Projects"],"parameters":[{"schema":{"type":"string"},"in":"path","name":"projectId","required":true}],"summary":"Get project memory"},"put":{"responses":{"200":{"description":"Updated memory document"},"400":{"description":"Invalid request, or an attempt to delete the Default project, which cannot be deleted"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient scope or plan upgrade required"},"404":{"description":"Project or file not found"},"409":{"description":"Version or resource conflict"},"429":{"description":"Rate limited"}},"operationId":"putApiV1ProjectsByProjectIdMemory","tags":["Projects"],"parameters":[{"schema":{"type":"string"},"in":"path","name":"projectId","required":true}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"markdown":{"type":"string","maxLength":20000},"expectedVersion":{"type":"integer","minimum":0}},"required":["markdown","expectedVersion"]}}}},"summary":"Replace project memory","description":"Replace the full Markdown document using compare-and-set. expectedVersion must equal the current version or the API returns PROJECT_MEMORY_VERSION_CONFLICT."}},"/api/v1/projects/{projectId}/memory/lines":{"post":{"responses":{"200":{"description":"Updated memory document"},"400":{"description":"Invalid request, or an attempt to delete the Default project, which cannot be deleted"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient scope or plan upgrade required"},"404":{"description":"Project or file not found"},"409":{"description":"Version or resource conflict"},"429":{"description":"Rate limited"}},"operationId":"postApiV1ProjectsByProjectIdMemoryLines","tags":["Projects"],"parameters":[{"schema":{"type":"string"},"in":"path","name":"projectId","required":true}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"section":{"type":"string","enum":["About the client","Ranking preferences","Never","Pitch voice"]},"text":{"type":"string","minLength":1,"maxLength":300}},"required":["section","text"],"additionalProperties":false}}}},"summary":"Append one project-memory line","description":"Append one durable line to About the client, Ranking preferences, Never, or Pitch voice. Ranking preferences and Never require a reason after a colon. Lines are capped at 300 characters and retain API-key provenance."}},"/api/v1/projects/{projectId}/files":{"get":{"responses":{"200":{"description":"Project file summaries"},"400":{"description":"Invalid request, or an attempt to delete the Default project, which cannot be deleted"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient scope or plan upgrade required"},"404":{"description":"Project or file not found"},"409":{"description":"Version or resource conflict"},"429":{"description":"Rate limited"}},"operationId":"getApiV1ProjectsByProjectIdFiles","tags":["Projects"],"parameters":[{"schema":{"type":"string"},"in":"path","name":"projectId","required":true}],"summary":"List project files"},"post":{"responses":{"201":{"description":"Presigned upload created"},"400":{"description":"Invalid request, or an attempt to delete the Default project, which cannot be deleted"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient scope or plan upgrade required"},"404":{"description":"Project or file not found"},"409":{"description":"Version or resource conflict"},"429":{"description":"Rate limited"}},"operationId":"postApiV1ProjectsByProjectIdFiles","tags":["Projects"],"parameters":[{"schema":{"type":"string"},"in":"path","name":"projectId","required":true}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"title":{"type":"string","minLength":1,"maxLength":200},"mimeType":{"type":"string","enum":["application/pdf","application/vnd.openxmlformats-officedocument.wordprocessingml.document","text/plain","text/markdown"]},"byteSize":{"type":"integer","exclusiveMinimum":0,"maximum":4000000},"clientUploadKey":{"type":"string","minLength":1,"maxLength":64}},"required":["title","mimeType","byteSize"]}}}},"summary":"Create a presigned project-file upload","description":"Step 1 of the three-step binary upload flow: create the file, PUT the exact bytes to uploadUrl with the returned headers, then call the complete endpoint with the lowercase SHA-256 digest."}},"/api/v1/projects/{projectId}/files/{fileId}/complete":{"post":{"responses":{"200":{"description":"File accepted for extraction"},"400":{"description":"Invalid request, or an attempt to delete the Default project, which cannot be deleted"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient scope or plan upgrade required"},"404":{"description":"Project or file not found"},"409":{"description":"Version or resource conflict"},"429":{"description":"Rate limited"}},"operationId":"postApiV1ProjectsByProjectIdFilesByFileIdComplete","tags":["Projects"],"parameters":[{"schema":{"type":"string"},"in":"path","name":"projectId","required":true},{"schema":{"type":"string"},"in":"path","name":"fileId","required":true}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"sha256":{"type":"string","pattern":"^[a-f0-9]{64}$"}},"required":["sha256"]}}}},"summary":"Complete a project-file upload","description":"Step 3 of the presigned flow. Verify the stored byte count and SHA-256 digest, then start extraction."}},"/api/v1/projects/{projectId}/files/{fileId}":{"get":{"responses":{"200":{"description":"Project file status and details"},"400":{"description":"Invalid request, or an attempt to delete the Default project, which cannot be deleted"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient scope or plan upgrade required"},"404":{"description":"Project or file not found"},"409":{"description":"Version or resource conflict"},"429":{"description":"Rate limited"}},"operationId":"getApiV1ProjectsByProjectIdFilesByFileId","tags":["Projects"],"parameters":[{"schema":{"type":"string"},"in":"path","name":"projectId","required":true},{"schema":{"type":"string"},"in":"path","name":"fileId","required":true}],"summary":"Get a project file","description":"Poll this endpoint while status is extracting. Ready files include their generated description; failed files include failureCode."},"delete":{"responses":{"200":{"description":"Project file deleted"},"400":{"description":"Invalid request, or an attempt to delete the Default project, which cannot be deleted"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient scope or plan upgrade required"},"404":{"description":"Project or file not found"},"409":{"description":"Version or resource conflict"},"429":{"description":"Rate limited"}},"operationId":"deleteApiV1ProjectsByProjectIdFilesByFileId","tags":["Projects"],"parameters":[{"schema":{"type":"string"},"in":"path","name":"projectId","required":true},{"schema":{"type":"string"},"in":"path","name":"fileId","required":true}],"summary":"Delete a project file"}},"/api/v1/projects/{projectId}":{"get":{"responses":{"200":{"description":"Project details and counts"},"400":{"description":"Invalid request, or an attempt to delete the Default project, which cannot be deleted"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient scope or plan upgrade required"},"404":{"description":"Project or file not found"},"409":{"description":"Version or resource conflict"},"429":{"description":"Rate limited"}},"operationId":"getApiV1ProjectsByProjectId","tags":["Projects"],"parameters":[{"schema":{"type":"string"},"in":"path","name":"projectId","required":true}],"summary":"Get a project"},"patch":{"responses":{"200":{"description":"Project updated"},"400":{"description":"Invalid request, or an attempt to delete the Default project, which cannot be deleted"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient scope or plan upgrade required"},"404":{"description":"Project or file not found"},"409":{"description":"Version or resource conflict"},"429":{"description":"Rate limited"}},"operationId":"patchApiV1ProjectsByProjectId","tags":["Projects"],"parameters":[{"schema":{"type":"string"},"in":"path","name":"projectId","required":true}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":120},"description":{"type":["string","null"],"maxLength":2000}}}}}},"summary":"Update a project","description":"Update a project name and/or description."},"delete":{"responses":{"200":{"description":"Deleted or archived disposition"},"400":{"description":"Invalid request, or an attempt to delete the Default project, which cannot be deleted"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient scope or plan upgrade required"},"404":{"description":"Project or file not found"},"409":{"description":"Version or resource conflict"},"429":{"description":"Rate limited"}},"operationId":"deleteApiV1ProjectsByProjectId","tags":["Projects"],"parameters":[{"schema":{"type":"string"},"in":"path","name":"projectId","required":true}],"summary":"Delete or archive a project","description":"Empty projects are deleted. Projects with files, media lists, campaigns, or agent history are archived so their lists remain reachable."}},"/api/v1/projects/{projectId}/radar":{"get":{"responses":{"200":{"description":"Radar, latest run, and plan limits"},"400":{"description":"Invalid RADAR.md or request body"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient scope, flag disabled, or plan limit"},"404":{"description":"Project not found"},"409":{"description":"Radar already exists"},"429":{"description":"Rate limited"}},"operationId":"getApiV1ProjectsByProjectIdRadar","tags":["Projects"],"parameters":[{"in":"query","name":"days","schema":{"type":"integer","minimum":1,"maximum":30,"default":1}},{"in":"query","name":"limit","schema":{"type":"integer","minimum":1,"maximum":50,"default":50}},{"in":"query","name":"cursor","schema":{"type":"string","minLength":1,"maxLength":2048}},{"schema":{"type":"string"},"in":"path","name":"projectId","required":true}],"summary":"Get a project Radar","description":"Returns RADAR.md to the authenticated agent on every plan; the file remains agent-managed when direct context editing is unavailable."},"put":{"responses":{"200":{"description":"Radar updated"},"400":{"description":"Invalid RADAR.md or request body"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient scope, flag disabled, or plan limit"},"404":{"description":"Project not found"},"409":{"description":"Radar already exists"},"429":{"description":"Rate limited"}},"operationId":"putApiV1ProjectsByProjectIdRadar","tags":["Projects"],"parameters":[{"schema":{"type":"string"},"in":"path","name":"projectId","required":true}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"markdown":{"type":"string","minLength":1,"maxLength":20000},"expected_version":{"type":"integer","minimum":0}},"required":["markdown","expected_version"],"additionalProperties":false}}}},"summary":"Replace a project RADAR.md","description":"Agent-managed compare-and-set update. Read the current version first and send it as expected_version."},"patch":{"responses":{"200":{"description":"Radar settings updated"},"400":{"description":"Invalid RADAR.md or request body"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient scope, flag disabled, or plan limit"},"404":{"description":"Project not found"},"409":{"description":"Radar already exists"},"429":{"description":"Rate limited"}},"operationId":"patchApiV1ProjectsByProjectIdRadar","tags":["Projects"],"parameters":[{"schema":{"type":"string"},"in":"path","name":"projectId","required":true}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","enum":["active","paused"]},"schedule_hour_local":{"type":"integer","minimum":0,"maximum":23},"email_digest_enabled":{"type":"boolean"},"slack_digest_enabled":{"type":"boolean"},"slack_webhook_url":{"anyOf":[{"type":"string","minLength":1,"maxLength":512},{"type":"string","const":""},{"type":"null"}]},"send_test":{"type":"boolean"}},"additionalProperties":false}}}},"summary":"Update project Radar settings"},"post":{"responses":{"201":{"description":"Radar created and optional run queued"},"400":{"description":"Invalid RADAR.md or request body"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient scope, flag disabled, or plan limit"},"404":{"description":"Project not found"},"409":{"description":"Radar already exists"},"429":{"description":"Rate limited"}},"operationId":"postApiV1ProjectsByProjectIdRadar","tags":["Projects"],"parameters":[{"schema":{"type":"string"},"in":"path","name":"projectId","required":true}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"markdown":{"type":"string","minLength":1,"maxLength":20000},"timezone":{"type":"string","minLength":1},"email_digest_enabled":{"type":"boolean"},"slack_digest_enabled":{"type":"boolean"},"slack_webhook_url":{"anyOf":[{"type":"string","minLength":1,"maxLength":512},{"type":"string","const":""},{"type":"null"}]},"send_test":{"type":"boolean"},"run_now":{"type":"boolean","default":true}},"required":["markdown"],"additionalProperties":false}}}},"summary":"Set up a project Radar","description":"Create an agent-managed RADAR.md and, by default, queue its first scan."}},"/api/v1/projects/{projectId}/radar/run":{"post":{"responses":{"202":{"description":"Radar run queued"},"400":{"description":"Invalid RADAR.md or request body"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient scope, flag disabled, or plan limit"},"404":{"description":"Project not found"},"409":{"description":"Radar already exists"},"429":{"description":"Rate limited"}},"operationId":"postApiV1ProjectsByProjectIdRadarRun","tags":["Projects"],"parameters":[{"schema":{"type":"string"},"in":"path","name":"projectId","required":true}],"summary":"Run a Radar scan now","description":"Queue an additional scan, subject to the two-Scan-now-runs-per-Radar-local-day limit."}},"/api/v1/projects/{projectId}/radar/runs":{"get":{"responses":{"200":{"description":"Radar run history with funnel counts"},"400":{"description":"Invalid RADAR.md or request body"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient scope, flag disabled, or plan limit"},"404":{"description":"Project not found"},"409":{"description":"Radar already exists"},"429":{"description":"Rate limited"}},"operationId":"getApiV1ProjectsByProjectIdRadarRuns","tags":["Projects"],"parameters":[{"in":"query","name":"limit","schema":{"type":"integer","minimum":1,"maximum":50}},{"schema":{"type":"string"},"in":"path","name":"projectId","required":true}],"summary":"List project Radar runs"}},"/api/v1/projects/{projectId}/radar/runs/{runId}":{"get":{"responses":{"200":{"description":"Radar run and opportunities"},"400":{"description":"Invalid RADAR.md or request body"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient scope, flag disabled, or plan limit"},"404":{"description":"Project not found"},"409":{"description":"Radar already exists"},"429":{"description":"Rate limited"}},"operationId":"getApiV1ProjectsByProjectIdRadarRunsByRunId","tags":["Projects"],"parameters":[{"schema":{"type":"string"},"in":"path","name":"projectId","required":true},{"schema":{"type":"string"},"in":"path","name":"runId","required":true}],"summary":"Get a project Radar run"}},"/api/v1/projects/{projectId}/radar/opportunities/{opportunityId}/feedback":{"post":{"responses":{"200":{"description":"Feedback recorded"},"400":{"description":"Invalid RADAR.md or request body"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient scope, flag disabled, or plan limit"},"404":{"description":"Project not found"},"409":{"description":"Radar already exists"},"429":{"description":"Rate limited"}},"operationId":"postApiV1ProjectsByProjectIdRadarOpportunitiesByOpportunityIdFeedback","tags":["Projects"],"parameters":[{"schema":{"type":"string"},"in":"path","name":"projectId","required":true},{"schema":{"type":"string"},"in":"path","name":"opportunityId","required":true}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"verdict":{"type":"string","enum":["more_like_this","fewer_like_this","wrong_company","too_stale","never_pitch","not_our_expertise","undo"]},"note":{"type":"string","maxLength":500}},"required":["verdict"]}}}},"summary":"Record Radar opportunity feedback"}},"/api/v1/radar/today":{"get":{"responses":{"200":{"description":"Today's Radar across projects"},"400":{"description":"Invalid RADAR.md or request body"},"401":{"description":"Unauthorized"},"403":{"description":"Insufficient scope, flag disabled, or plan limit"},"404":{"description":"Project not found"},"409":{"description":"Radar already exists"},"429":{"description":"Rate limited"}},"operationId":"getApiV1RadarToday","tags":["Radar"],"parameters":[{"in":"query","name":"include_empty_projects","schema":{"type":"string","enum":["true","false"]}},{"in":"query","name":"limit","schema":{"type":"integer","minimum":1,"maximum":50,"default":20}},{"in":"query","name":"cursor","schema":{"type":"string","minLength":1,"maxLength":2048}}],"summary":"Get today's organization Radar"}},"/api/v1/credits/balance":{"get":{"responses":{"200":{"description":"Credit balance"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"429":{"description":"Free-tier public API access is temporarily paused due to high traffic"}},"operationId":"getApiV1CreditsBalance","tags":["Medialyst API"],"parameters":[],"summary":"Get credit balance","description":"Return the authenticated organization's current credit balance. Use this before cost-incurring API calls."}},"/api/v1/journalist-moves":{"get":{"responses":{"200":{"description":"A bounded, de-duplicated journalist-move page","content":{"application/json":{"schema":{"type":"object","properties":{"moves":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","pattern":"^jm_[A-Za-z0-9_-]{24}$"},"name":{"type":"string"},"normalized_name":{"type":["string","null"]},"old_outlet":{"type":["string","null"]},"new_outlet":{"type":["string","null"]},"kind":{"type":"string","minLength":1,"maxLength":32},"role":{"type":["string","null"]},"beat":{"type":["string","null"]},"effective_date_text":{"type":["string","null"]},"match_state":{"type":"string","minLength":1,"maxLength":64},"journalist_identity_id":{"type":["string","null"]},"observed_at":{"type":"string","format":"date-time"},"published_at":{"type":["string","null"],"format":"date-time"},"sources":{"type":"array","items":{"type":"object","properties":{"source_id":{"type":"string","minLength":1,"maxLength":128},"source_url":{"type":["string","null"],"format":"uri","maxLength":2048},"evidence_quote":{"type":"string"},"observed_at":{"type":"string","format":"date-time"},"published_at":{"type":["string","null"],"format":"date-time"},"kind":{"type":"string","minLength":1,"maxLength":32},"match_state":{"type":"string","minLength":1,"maxLength":64},"extraction_lane":{"type":"string","minLength":1,"maxLength":64}},"required":["source_id","source_url","evidence_quote","observed_at","published_at","kind","match_state","extraction_lane"],"additionalProperties":false},"minItems":1}},"required":["id","name","normalized_name","old_outlet","new_outlet","kind","role","beat","effective_date_text","match_state","journalist_identity_id","observed_at","published_at","sources"],"additionalProperties":false}},"page":{"type":"object","properties":{"count":{"type":"integer","minimum":0,"maximum":250},"has_more":{"type":"boolean"},"next_cursor":{"type":"string","minLength":1,"maxLength":2048},"watermark":{"type":"string","format":"date-time"}},"required":["count","has_more","next_cursor","watermark"],"additionalProperties":false},"request_id":{"type":"string","minLength":1}},"required":["moves","page","request_id"],"additionalProperties":false}}}},"400":{"description":"Invalid timestamp, cursor, or limit"},"401":{"description":"Missing or invalid credential"},"403":{"description":"Credential's organization is not on an active Scale plan"},"429":{"description":"Rate limited or free-tier traffic temporarily shed"}},"operationId":"getApiV1Journalist-moves","tags":["Medialyst API"],"parameters":[{"in":"query","name":"since","schema":{"type":"string","format":"date-time"}},{"in":"query","name":"cursor","schema":{"type":"string","minLength":1,"maxLength":2048}},{"in":"query","name":"limit","schema":{"type":"integer","minimum":1,"maximum":250,"default":100}},{"in":"query","name":"kind","schema":{"type":"string","minLength":1,"maxLength":64}}],"summary":"Poll journalist outlet moves","description":"Return de-duplicated journalist outlet-move records observed after an exclusive timestamp or opaque cursor. `since` filters on when Medialyst observed each move — not the move's effective date — so a poller receives late-reported moves. Results are ordered by observed_at then stable id and collapse corroborating sources into one record. Each record carries `kind` (move, promotion, departure; filter with the optional `kind` query param) and `match_state`, which only says whether the name resolved to a Medialyst journalist record — not whether the move is real. Requires an active Scale-plan credential; calls are free and cost 0 credits."}},"/api/v1/news/search":{"post":{"responses":{"200":{"description":"News search response","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"link":{"type":"string"},"url_status":{"type":"string","enum":["publisher","opaque"],"description":"Whether link is a publisher URL or an opaque wrapper; opaque means the link is a Google News redirect wrapper, not a publisher URL."},"metadata":{"type":"object","properties":{"publication_type":{"type":"string","nullable":true,"enum":["editorial","brand_content","newswire","government","syndication_platform","other",null]},"domain_authority":{"type":"number","nullable":true},"estimated_monthly_organic_traffic":{"type":"number","nullable":true}},"required":["publication_type","domain_authority","estimated_monthly_organic_traffic"],"additionalProperties":true}},"additionalProperties":true}},"results":{"type":"array","items":{"type":"object","properties":{"link":{"type":"string"},"url_status":{"type":"string","enum":["publisher","opaque"],"description":"Whether link is a publisher URL or an opaque wrapper; opaque means the link is a Google News redirect wrapper, not a publisher URL."},"metadata":{"type":"object","properties":{"publication_type":{"type":"string","nullable":true,"enum":["editorial","brand_content","newswire","government","syndication_platform","other",null]},"domain_authority":{"type":"number","nullable":true},"estimated_monthly_organic_traffic":{"type":"number","nullable":true}},"required":["publication_type","domain_authority","estimated_monthly_organic_traffic"],"additionalProperties":true}},"additionalProperties":true}},"news":{"type":"array","items":{"type":"object","properties":{"link":{"type":"string"},"url_status":{"type":"string","enum":["publisher","opaque"],"description":"Whether link is a publisher URL or an opaque wrapper; opaque means the link is a Google News redirect wrapper, not a publisher URL."},"metadata":{"type":"object","properties":{"publication_type":{"type":"string","nullable":true,"enum":["editorial","brand_content","newswire","government","syndication_platform","other",null]},"domain_authority":{"type":"number","nullable":true},"estimated_monthly_organic_traffic":{"type":"number","nullable":true}},"required":["publication_type","domain_authority","estimated_monthly_organic_traffic"],"additionalProperties":true}},"additionalProperties":true}},"articles":{"type":"array","items":{"type":"object","properties":{"link":{"type":"string"},"url_status":{"type":"string","enum":["publisher","opaque"],"description":"Whether link is a publisher URL or an opaque wrapper; opaque means the link is a Google News redirect wrapper, not a publisher URL."},"metadata":{"type":"object","properties":{"publication_type":{"type":"string","nullable":true,"enum":["editorial","brand_content","newswire","government","syndication_platform","other",null]},"domain_authority":{"type":"number","nullable":true},"estimated_monthly_organic_traffic":{"type":"number","nullable":true}},"required":["publication_type","domain_authority","estimated_monthly_organic_traffic"],"additionalProperties":true}},"additionalProperties":true}},"organic":{"type":"array","items":{"type":"object","properties":{"link":{"type":"string"},"url_status":{"type":"string","enum":["publisher","opaque"],"description":"Whether link is a publisher URL or an opaque wrapper; opaque means the link is a Google News redirect wrapper, not a publisher URL."},"metadata":{"type":"object","properties":{"publication_type":{"type":"string","nullable":true,"enum":["editorial","brand_content","newswire","government","syndication_platform","other",null]},"domain_authority":{"type":"number","nullable":true},"estimated_monthly_organic_traffic":{"type":"number","nullable":true}},"required":["publication_type","domain_authority","estimated_monthly_organic_traffic"],"additionalProperties":true}},"additionalProperties":true}}},"additionalProperties":true}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"402":{"description":"Payment Required"},"429":{"description":"Rate limited"},"500":{"description":"Internal configuration or billing error"}},"operationId":"postApiV1NewsSearch","tags":["Medialyst API"],"parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"required":["q"],"properties":{"q":{"type":"string","description":"News search query."},"gl":{"type":"string","description":"Country code, such as us."},"hl":{"type":"string","description":"Interface language, such as en."},"page":{"type":"integer","minimum":1,"maximum":10,"description":"1-based page. Each page returns up to 10 results."},"tbs":{"type":"string","description":"Time filter, such as qdr:m."}}},"example":{"q":"\"AI infrastructure\" startup funding","gl":"us","page":2,"tbs":"qdr:m"}}}},"summary":"News search","description":"Search current news results for a query. Use page for deeper results; each page returns up to 10 items. Responses include news results plus Medialyst source classification metadata when available."}},"/api/v1/pr-calendar/query":{"post":{"responses":{"200":{"description":"PR calendar query response"},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"429":{"description":"Rate limited"}},"operationId":"postApiV1Pr-calendarQuery","tags":["Medialyst API"],"parameters":[],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"q":{"type":"string","minLength":1,"maxLength":500},"industries":{"type":"array","items":{"type":"string","enum":["tech","fin","health","retail","media","food"]},"minItems":1,"maxItems":6},"types":{"type":"array","items":{"type":"string","minLength":1,"maxLength":100},"maxItems":25},"tags":{"type":"array","items":{"type":"string","minLength":1,"maxLength":100},"maxItems":25},"audiences":{"type":"array","items":{"type":"string","minLength":1,"maxLength":100},"maxItems":25},"country_codes":{"type":"array","items":{"type":"string","minLength":1,"maxLength":100},"maxItems":25},"start_date":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"end_date":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"pitch_start_before":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"pitch_deadline_after":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"limit":{"type":"integer","minimum":1,"maximum":100,"default":25},"cursor":{"type":"string","minLength":1,"maxLength":500}},"additionalProperties":false}}}},"summary":"Query PR calendar","description":"Query Medialyst's PR calendar for source-backed awareness days, conferences, retail peaks, and cultural moments. Successful calls are free and cost 0 credits."}},"/api/v1/journalists/enrich":{"post":{"responses":{"200":{"description":"Completed idempotent replay"},"202":{"description":"Enrichment job accepted"},"400":{"description":"Invalid request, including PUBLICATION_NOT_FOUND when a publication-only reference cannot be mapped to a unique domain"},"401":{"description":"Unauthorized"},"402":{"description":"Payment Required"},"403":{"description":"Forbidden"},"409":{"description":"Idempotency conflict"},"429":{"description":"Too many active jobs"},"500":{"description":"Failed to start enrichment job"}},"operationId":"postApiV1JournalistsEnrich","tags":["Medialyst API"],"parameters":[],"requestBody":{"required":true,"content":{"application/json":{"example":{"from":[{"type":"journalist_reference","name":"Jane Doe","publication":"The Daily Example"}]}}}},"summary":"Enrich journalists from references or source articles","description":"Submit journalist_reference sources or article_url sources and immediately receive a durable enrichment job. Each journalist_reference requires name plus at least one of publication, domain, or URL. Publication-only references are mapped to a canonical domain when the publication is known; otherwise the request returns PUBLICATION_NOT_FOUND and should be retried with domain supplied. Poll GET /v1/journalist-enrichment-jobs/:jobId until the job is complete or failed. Include fit_context.pitch to also receive current journalist_research_v1 fit score, reasoning, and personalized angle results."}},"/api/v1/journalist-enrichment-jobs/{jobId}":{"get":{"responses":{"200":{"description":"Journalist enrichment job"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"404":{"description":"Not found"}},"operationId":"getApiV1Journalist-enrichment-jobsByJobId","tags":["Medialyst API"],"parameters":[{"schema":{"type":"string"},"in":"path","name":"jobId","required":true}],"summary":"Get journalist enrichment job status"}},"/api/v1/publications/lookup":{"get":{"responses":{"200":{"description":"Publication metadata"},"400":{"description":"Invalid URL or request"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"429":{"description":"Rate limited"},"500":{"description":"Configuration error"},"502":{"description":"Provider lookup failed"}},"operationId":"getApiV1PublicationsLookup","tags":["Medialyst API"],"parameters":[{"in":"query","name":"url","schema":{"type":"string","minLength":1},"required":true},{"in":"query","name":"force_refresh","schema":{"anyOf":[{"type":"string","const":"true"},{"type":"string","const":"false"},{"type":"string","const":"1"},{"type":"string","const":"0"}]},"required":false}],"summary":"Lookup publication metadata","description":"Resolve a URL to Medialyst publication metadata. Cached rows are reused while fresh; stale or missing metrics are scraped through the publication metrics pipeline and written back."}},"/api/v1/publications/lookup:batch":{"post":{"responses":{"200":{"description":"Publication metadata batch results"},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"429":{"description":"Rate limited"},"500":{"description":"Configuration error"},"502":{"description":"Provider lookup failed"}},"operationId":"postApiV1PublicationsLookup:batch","tags":["Medialyst API"],"parameters":[{"in":"query","name":"force_refresh","schema":{"anyOf":[{"type":"string","const":"true"},{"type":"string","const":"false"},{"type":"string","const":"1"},{"type":"string","const":"0"}]}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"urls":{"type":"array","items":{"type":"string","minLength":1},"minItems":1,"maxItems":25}},"required":["urls"],"additionalProperties":false}}}},"summary":"Batch lookup publication metadata","description":"Resolve up to 25 URLs to publication metadata. Results preserve input order and report per-URL errors so agents can continue after partial failures."}},"/api/v1/articles/lookup":{"get":{"responses":{"200":{"description":"Article lookup result"},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"402":{"description":"Payment Required"},"403":{"description":"Forbidden"},"429":{"description":"Rate limited"},"500":{"description":"Configuration error"},"502":{"description":"Article lookup failed"}},"operationId":"getApiV1ArticlesLookup","tags":["Medialyst API"],"parameters":[{"in":"query","name":"url","required":true,"description":"Absolute http(s) URL of the article to look up, e.g. https://example.com/story.","schema":{"type":"string","minLength":1}},{"in":"query","name":"include","required":false,"description":"Optional. Only `markdown` is supported; it adds the extracted article body as a `markdown` field. Author details are always included by default, so there is no `authors` include.","schema":{"type":"string","enum":["markdown"]}}],"summary":"Look up article metadata and optional Markdown"}},"/api/v1/articles/lookup:batch":{"post":{"responses":{"200":{"description":"Article lookup batch results"},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden"},"429":{"description":"Rate limited"}},"operationId":"postApiV1ArticlesLookup:batch","tags":["Medialyst API"],"parameters":[],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"urls":{"type":"array","items":{"type":"string","minLength":1},"minItems":1,"maxItems":10}},"required":["urls"],"additionalProperties":false}}}},"summary":"Look up multiple articles"}},"/api/v1/media-lists:create-async":{"post":{"responses":{"202":{"description":"Job accepted and durable media-list resource created","content":{"application/json":{"schema":{"type":"object","properties":{"media_list_id":{"type":["string","null"]},"workflow_id":{"type":["string","null"]},"media_list_url":{"type":["string","null"],"format":"uri"},"results_url":{"type":["string","null"],"format":"uri"},"job_id":{"type":"string"},"status":{"type":"string"},"target_list_size":{"type":"integer","exclusiveMinimum":0},"status_url":{"type":"string"}},"required":["media_list_id","workflow_id","media_list_url","results_url","job_id","status","target_list_size","status_url"]},"example":{"job_id":"job_01HT...","status":"pending","target_list_size":50,"status_url":"/api/v1/jobs/job_01HT...","media_list_id":"tbl_01HS...","workflow_id":"tbl_01HS...","media_list_url":"https://medialyst.ai/app/media-lists/tbl_01HS...","results_url":"https://medialyst.ai/api/v1/media-lists/tbl_01HS...?include_rows=true&row_detail=full&limit=100"}}}},"400":{"description":"Invalid request"},"401":{"description":"Unauthorized"},"402":{"description":"Payment Required"},"409":{"description":"Idempotency conflict"},"429":{"description":"Rate limited"}},"operationId":"postApiV1Media-lists:create-async","tags":["Medialyst API"],"parameters":[],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"prompt":{"type":"string","minLength":1,"maxLength":2000},"topic":{"type":"string","minLength":1,"maxLength":2000},"target_list_size":{"type":"integer","minimum":1,"maximum":1000},"max_articles":{"type":"integer","minimum":1,"maximum":1000}}}}}},"summary":"Create a media list asynchronously","description":"Create the durable organization-scoped media-list table before dispatching background discovery. Newly accepted jobs include an authenticated app URL that is safe to post to collaborators; it is not a public share link. A replay of a legacy table-less job may return null resource locators until the worker attaches its table. Poll status_url for progress and use results_url for the full first-party table data."}},"/api/v1/jobs/{jobId}":{"get":{"responses":{"200":{"description":"Job status and durable media-list links","content":{"application/json":{"schema":{"type":"object","properties":{"media_list_id":{"type":["string","null"]},"workflow_id":{"type":["string","null"]},"media_list_url":{"type":["string","null"],"format":"uri"},"results_url":{"type":["string","null"],"format":"uri"},"job_id":{"type":"string"},"status":{"type":"string"},"stage":{"type":"string","enum":["planning","enrichment","beat_sweep","done","failed","cancelled"]},"target_list_size":{"type":"integer","exclusiveMinimum":0},"created_at":{"type":["string","null"],"format":"date-time"},"updated_at":{"type":["string","null"],"format":"date-time"},"completed_at":{"type":["string","null"],"format":"date-time"},"progress":{"type":["object","null"],"properties":{"stage":{"type":"string"},"percent":{"type":"number"},"message":{"type":"string"}}},"result":{"type":["object","null"],"properties":{"workflow_id":{"type":"string"},"total_rows":{"type":"integer","minimum":0},"ready_rows":{"type":"integer","minimum":0},"failed_rows":{"type":"integer","minimum":0}},"required":["workflow_id","total_rows","ready_rows","failed_rows"]},"beat_sweep":{"type":["object","null"],"properties":{"status":{"type":"string"},"rows_added":{"type":"integer","minimum":0},"run_id":{"type":"string"},"reason":{"type":"string"}},"required":["status","rows_added"]},"budget":{"type":["object","null"],"properties":{"credits":{"type":"number","minimum":0},"spent":{"type":"number","minimum":0},"reserved":{"type":"number","minimum":0}},"required":["credits","spent","reserved"]},"error":{},"rows":{"type":"array","items":{"type":"object","additionalProperties":{}}},"page":{"type":"object","properties":{"next_cursor":{"type":["string","null"]}},"required":["next_cursor"]}},"required":["media_list_id","workflow_id","media_list_url","results_url","job_id","status","stage","target_list_size","created_at","updated_at","completed_at","progress","result","beat_sweep","budget"]}}}},"401":{"description":"Unauthorized"},"404":{"description":"Not found"}},"operationId":"getApiV1JobsByJobId","tags":["Medialyst API"],"parameters":[{"schema":{"type":"string"},"in":"path","name":"jobId","required":true}],"summary":"Get media list job status","description":"Poll an asynchronous media-list job. Resource identifiers and the authenticated Medialyst app/results URLs remain stable from the initial pending response through processing and completion."}}},"components":{"schemas":{}}}