Getting Started
The Coverage Report API lets you generate PR coverage reports without using the web interface. Submit a list of media coverage URLs, and we return a polished report with screenshots, Domain Authority, traffic metrics, and more.
Quick Start
- Create an account at app.coveragereport.ai
- Go to Settings → API Keys and create a new key
- Copy the key (it is only shown once)
- Pass the key in every request as the
X-API-Keyheader
Authentication
All API requests require an API key passed via the X-API-Key HTTP header. Keys are prefixed with cr_live_ and are scoped to your account.
X-API-Key: cr_live_abc123def456...
If the key is missing, invalid, or revoked, the API returns 401 Unauthorized.
Rate Limits
API requests are rate-limited to 60 requests per minute per API key. If you exceed the limit, the API returns 429 Too Many Requests.
Rate limit windows are rolling. After receiving a 429 response, wait briefly before retrying. The limit resets every 60 seconds.
Get Credit Balance
Returns the current credit balance for the authenticated account.
{
"balance": 12
}
curl https://app.coveragereport.ai/api/v1/credits/balance \
-H "X-API-Key: cr_live_YOUR_KEY"
Create Report
Submit an array of URLs to generate a coverage report. The report is processed asynchronously — poll the Get Report Status endpoint to check progress. Credits are deducted immediately.
| Parameter | Type | Description |
|---|---|---|
| urls Required | string[] | Array of coverage URLs to include in the report. Maximum 500 URLs per request. Duplicates are removed automatically. |
| reportName Optional | string | A name for the report. Defaults to "Untitled" if omitted. |
{
"id": "a1b2c3d4e5f6...",
"status": "processing",
"urlCount": 15,
"creditsUsed": 1,
"message": "Report is being generated. Poll GET /api/v1/reports/a1b2c3d4e5f6... for status."
}
curl -X POST https://app.coveragereport.ai/api/v1/reports \
-H "X-API-Key: cr_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"urls": [
"https://www.bbc.co.uk/news/example-article",
"https://www.theguardian.com/example-story",
"https://techcrunch.com/2026/01/example"
],
"reportName": "January Campaign"
}'
Get Report Status
Retrieve the status and details of a report. When the status is completed, the response includes a shareable URL and aggregate stats.
| Parameter | Type | Description |
|---|---|---|
| id Required | string | The report ID returned from the Create Report endpoint. |
{
"id": "a1b2c3d4e5f6...",
"status": "processing",
"reportName": "January Campaign",
"urlCount": 15,
"creditsUsed": 1,
"createdAt": "2026-04-05T10:30:00.000Z",
"completedAt": null
}
{
"id": "a1b2c3d4e5f6...",
"status": "completed",
"reportName": "January Campaign",
"urlCount": 15,
"creditsUsed": 1,
"createdAt": "2026-04-05T10:30:00.000Z",
"completedAt": "2026-04-05T10:31:42.000Z",
"shareUrl": "https://app.coveragereport.ai/api/portal/reports/share/abc123...",
"stats": {
"totalLinks": 15,
"screenshots": 12
}
}
{
"id": "a1b2c3d4e5f6...",
"status": "failed",
"error": "Description of what went wrong",
...
}
curl https://app.coveragereport.ai/api/v1/reports/a1b2c3d4e5f6... \
-H "X-API-Key: cr_live_YOUR_KEY"
Get Report HTML
Returns the fully rendered HTML report. Only available for completed reports. The response Content-Type is text/html. Useful for embedding in your own dashboards or converting to PDF.
| Parameter | Type | Description |
|---|---|---|
| id Required | string | The report ID. |
Returns 409 Conflict if the report is still processing, or 404 Not Found if the report does not exist.
# Save the rendered report to a file
curl https://app.coveragereport.ai/api/v1/reports/a1b2c3d4e5f6.../html \
-H "X-API-Key: cr_live_YOUR_KEY" \
-o report.html
List Reports
Returns a list of your most recent reports, ordered by creation date (newest first).
| Parameter | Type | Description |
|---|---|---|
| limit Optional | integer | Number of reports to return. Default: 20, maximum: 100. |
{
"data": [
{
"id": "a1b2c3d4e5f6...",
"status": "completed",
"reportName": "January Campaign",
"urlCount": 15,
"creditsUsed": 1,
"createdAt": "2026-04-05T10:30:00.000Z",
"completedAt": "2026-04-05T10:31:42.000Z"
},
...
]
}
curl "https://app.coveragereport.ai/api/v1/reports?limit=50" \
-H "X-API-Key: cr_live_YOUR_KEY"
Credit Pricing
Each report consumes credits based on the number of URLs submitted. Credits are deducted when you create the report, before processing begins.
| URLs in Report | Credits Used |
|---|---|
| 1 – 100 | 1 credit |
| 101 – 250 | 2 credits |
| 251 – 500 | 3 credits |
| 501+ | 3 + 1 per additional 250 URLs |
For example: a report with 600 URLs costs 3 + ceil((600 − 500) / 250) = 4 credits. A report with 1,000 URLs costs 3 + ceil((1000 − 500) / 250) = 5 credits.
Error Codes
All errors return a JSON object with an error field containing a human-readable message. Some errors include additional context fields.
| Status | Meaning | Description |
|---|---|---|
| 400 | Bad Request | Invalid request body. The urls array is missing, empty, or exceeds 500 items. Or no valid URLs were found after cleaning. |
| 401 | Unauthorized | The X-API-Key header is missing, the key does not start with cr_live_, or the key has been revoked. |
| 402 | Payment Required | Insufficient credits. The response includes required (credits needed) and available (current balance) fields. |
| 403 | Forbidden | Account is deactivated. |
| 404 | Not Found | The requested report does not exist or does not belong to your account. |
| 409 | Conflict | Returned by the HTML endpoint when the report is still processing. Includes the current status. |
| 429 | Too Many Requests | Rate limit exceeded. Wait before retrying. Limit: 60 requests per minute per API key. |
| 500 | Server Error | Unexpected server error. If this persists, contact support. |
Error Response Examples
{
"error": "Missing or invalid API key. Pass X-API-Key header."
}
{
"error": "Insufficient credits",
"required": 2,
"available": 1
}
{
"error": "Report not ready yet",
"status": "processing"
}
Code Examples
Full working examples showing how to create a report and poll for completion. Replace cr_live_YOUR_KEY with your actual API key.
#!/bin/bash
# Create a coverage report and poll until complete
API_KEY="cr_live_YOUR_KEY"
BASE="https://app.coveragereport.ai/api/v1"
# 1. Check balance
curl -s "$BASE/credits/balance" -H "X-API-Key: $API_KEY"
# 2. Create report
RESPONSE=$(curl -s -X POST "$BASE/reports" \
-H "X-API-Key: $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"urls": [
"https://www.bbc.co.uk/news/example",
"https://www.theguardian.com/example"
],
"reportName": "Q1 Coverage"
}')
REPORT_ID=$(echo "$RESPONSE" | jq -r '.id')
echo "Report created: $REPORT_ID"
# 3. Poll for completion
while true; do
STATUS=$(curl -s "$BASE/reports/$REPORT_ID" \
-H "X-API-Key: $API_KEY" | jq -r '.status')
echo "Status: $STATUS"
if [ "$STATUS" != "processing" ]; then break; fi
sleep 5
done
# 4. Download HTML report
curl -s "$BASE/reports/$REPORT_ID/html" \
-H "X-API-Key: $API_KEY" -o report.html
echo "Report saved to report.html"
import requests
import time
API_KEY = "cr_live_YOUR_KEY"
BASE_URL = "https://app.coveragereport.ai/api/v1"
headers = {"X-API-Key": API_KEY}
# 1. Check credit balance
balance = requests.get(
f"{BASE_URL}/credits/balance",
headers=headers,
).json()
print(f"Credits available: {balance['balance']}")
# 2. Create a report
report = requests.post(
f"{BASE_URL}/reports",
headers=headers,
json={
"urls": [
"https://www.bbc.co.uk/news/example",
"https://www.theguardian.com/example",
"https://techcrunch.com/2026/01/example",
],
"reportName": "Q1 Coverage Report",
},
).json()
report_id = report["id"]
print(f"Report created: {report_id} ({report['creditsUsed']} credits)")
# 3. Poll until complete
while True:
status = requests.get(
f"{BASE_URL}/reports/{report_id}",
headers=headers,
).json()
print(f"Status: {status['status']}")
if status["status"] != "processing":
break
time.sleep(5)
# 4. Get results
if status["status"] == "completed":
print(f"Share URL: {status['shareUrl']}")
print(f"Stats: {status['stats']}")
# Download HTML
html = requests.get(
f"{BASE_URL}/reports/{report_id}/html",
headers=headers,
)
with open("report.html", "w") as f:
f.write(html.text)
print("Report saved to report.html")
else:
print(f"Report failed: {status.get('error')}")
const API_KEY = "cr_live_YOUR_KEY";
const BASE_URL = "https://app.coveragereport.ai/api/v1";
const headers = {
"X-API-Key": API_KEY,
"Content-Type": "application/json",
};
async function generateReport() {
// 1. Check balance
const balanceRes = await fetch(`${BASE_URL}/credits/balance`, { headers });
const { balance } = await balanceRes.json();
console.log(`Credits available: ${balance}`);
// 2. Create report
const createRes = await fetch(`${BASE_URL}/reports`, {
method: "POST",
headers,
body: JSON.stringify({
urls: [
"https://www.bbc.co.uk/news/example",
"https://www.theguardian.com/example",
"https://techcrunch.com/2026/01/example",
],
reportName: "Q1 Coverage Report",
}),
});
const report = await createRes.json();
console.log(`Report created: ${report.id} (${report.creditsUsed} credits)`);
// 3. Poll until complete
let status;
do {
await new Promise((r) => setTimeout(r, 5000));
const res = await fetch(`${BASE_URL}/reports/${report.id}`, { headers });
status = await res.json();
console.log(`Status: ${status.status}`);
} while (status.status === "processing");
// 4. Get results
if (status.status === "completed") {
console.log(`Share URL: ${status.shareUrl}`);
console.log(`Stats:`, status.stats);
// Download HTML
const htmlRes = await fetch(
`${BASE_URL}/reports/${report.id}/html`,
{ headers }
);
const html = await htmlRes.text();
console.log(`HTML report: ${html.length} chars`);
} else {
console.error(`Report failed: ${status.error}`);
}
}
generateReport();
Managing API Keys
API keys are managed from the Coverage Report dashboard. You can also manage them programmatically via the portal endpoints (session-authenticated, not API key).
Creating a Key
Navigate to Settings → API Keys in the dashboard and click Create API Key. Give it a descriptive name. The full key is shown once — copy it immediately. Only the prefix (cr_live_XXXXXXXX) is stored for identification.
Limits
Each account can have up to 5 active API keys. Only owners and admins can create or revoke keys; team members with the "member" role cannot.
Revoking a Key
From the same Settings page, click the revoke button next to any key. Revoked keys stop working immediately and cannot be re-enabled — you will need to create a new key.
last_used_at timestamp and request_count, visible in the dashboard. Use this to audit which keys are active and identify unused keys you should revoke.