URL Font Scanner API
Scan any web page for fonts and get a licensing compliance report. Version 3.
Base URL
https://api.lipi.ai/v3
Authentication
All requests require an API key passed in the x-api-key header. Same API key as the Font Match API.
curl https://api.lipi.ai/v3/credits \ -H "x-api-key: lpi_your_api_key_here"
Endpoints
/v3/url-scanSubmit URL for font compliance scanning1 credit/v3/url-scan/:idPoll scan status and results/v3/creditsCheck credit balance/v3/usageUsage history (paginated)A headless browser navigates to your URL, detects all fonts on the page, and cross-references each against our license database. Processing takes 30-60 seconds. Cached results (7-day TTL) return instantly. Duplicate in-progress scans return the existing job without charging.
POST /v3/url-scan
Submit a URL for font detection and license compliance analysis.
Request
curl -X POST https://api.lipi.ai/v3/url-scan \
-H "x-api-key: lpi_your_api_key_here" \
-H "Content-Type: application/json" \
-d '{
"url": "https://stripe.com"
}'Response (201)
{
"job_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"status": "pending",
"url": "https://stripe.com",
"credits_charged": 1,
"credits_remaining": 99,
"free_credits_remaining": 7,
"poll_url": "/v3/url-scan/a1b2c3d4-e5f6-7890-abcd-ef1234567890"
}Response (cached)
If the same URL was scanned in the last 7 days, the cached result is returned immediately. Still costs 1 credit.
{
"cached": true,
"url": "https://stripe.com",
"credits_charged": 1,
"scanned_at": "2026-04-12T10:30:00Z",
"page_title": "Stripe | Financial Infrastructure",
"fonts_detected": [
{ "family": "Inter", "weights": ["400", "500", "700"], "source": "google_fonts" }
],
"license_results": [
{
"font_name": "Inter",
"risk_level": "low",
"license_type": "SIL Open Font License",
"commercial_use": true
}
],
"compliance_summary": {
"total_fonts": 1,
"low_risk": 1,
"medium_risk": 0,
"high_risk": 0,
"unknown_risk": 0,
"overall_score": 100,
"overall_risk": "low"
}
}GET /v3/url-scan/:id
Poll for scan completion. Poll every 3 seconds. Processing typically takes 30-60 seconds.
Response (running)
{
"job_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"status": "running",
"progress": 60,
"stage": "checking_licenses",
"url": "https://stripe.com",
"created_at": "2026-04-12T10:30:00Z",
"completed_at": null
}Response (succeeded)
{
"job_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"status": "succeeded",
"progress": 100,
"stage": "completed",
"url": "https://stripe.com",
"page_title": "Stripe | Financial Infrastructure",
"fonts_detected": [
{ "family": "Inter", "weights": ["400", "500", "700"], "source": "google_fonts" },
{ "family": "Söhne", "weights": ["400"], "source": "stylesheet" }
],
"license_results": [
{
"font_name": "Inter",
"risk_level": "low",
"license_type": "SIL Open Font License",
"commercial_use": true
},
{
"font_name": "Söhne",
"risk_level": "low",
"license_type": "Commercial (Klim Type Foundry)",
"commercial_use": true
}
],
"compliance_summary": {
"total_fonts": 2,
"low_risk": 2,
"medium_risk": 0,
"high_risk": 0,
"unknown_risk": 0,
"overall_score": 100,
"overall_risk": "low"
},
"created_at": "2026-04-12T10:30:00Z",
"completed_at": "2026-04-12T10:30:48Z"
}Response (failed)
{
"job_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"status": "failed",
"error": "Scan timed out after 80 seconds",
"url": "https://stripe.com",
"created_at": "2026-04-12T10:30:00Z",
"completed_at": "2026-04-12T10:31:20Z"
}Credits are automatically refunded for failed scans.
Error Codes
| Status | Error Code | Description |
|---|---|---|
| 400 | missing_url | No URL provided in request body |
| 401 | invalid_api_key | Missing or invalid API key |
| 402 | insufficient_credits | No credits remaining |
| 403 | key_suspended | API key has been suspended |
| 404 | not_found | Job not found or not owned by this key |
| 422 | invalid_url | Invalid URL, private IP, or non-HTTP scheme |
| 429 | rate_limited | Exceeded rate limit (see retry_after_seconds) |
| 503 | service_busy | High demand, retry shortly |
Rate Limits
Per Key
60 req/min
Response Header
429 responses include retry_after_seconds
Pricing
Free Tier
10 credits/month
Resets monthly. No card required.
Subscription
$75/month
100 credits. Unused credits roll over. Overage: $75/100 credits.
1 credit = 1 url-scan or 1 font-match request. Credits are shared across both APIs.
Code Examples
Python
import requests
import time
API_KEY = "lpi_your_api_key_here"
BASE = "https://api.lipi.ai/v3"
HEADERS = {"x-api-key": API_KEY, "Content-Type": "application/json"}
# Submit scan
resp = requests.post(f"{BASE}/url-scan", json={
"url": "https://stripe.com"
}, headers=HEADERS)
data = resp.json()
# If cached, results are already here
if data.get("cached"):
print(f"Cached result from {data['scanned_at']}")
for font in data["fonts_detected"]:
print(f" {font['family']}")
print(f"Compliance score: {data['compliance_summary']['overall_score']}%")
else:
# Poll for results
job_id = data["job_id"]
print(f"Job {job_id} created. Polling...")
while True:
time.sleep(3)
status = requests.get(f"{BASE}/url-scan/{job_id}", headers=HEADERS).json()
if status["status"] == "succeeded":
for font in status["fonts_detected"]:
print(f" {font['family']} — {font.get('source', 'unknown')}")
print(f"Compliance: {status['compliance_summary']['overall_risk']}")
break
elif status["status"] == "failed":
print(f"Failed: {status.get('error')}")
break
else:
print(f" {status['progress']}% — {status.get('stage', '')}")Node.js
const API_KEY = 'lpi_your_api_key_here';
const BASE = 'https://api.lipi.ai/v3';
const headers = { 'x-api-key': API_KEY, 'Content-Type': 'application/json' };
async function scanUrl(url) {
const res = await fetch(`${BASE}/url-scan`, {
method: 'POST',
headers,
body: JSON.stringify({ url })
});
const data = await res.json();
// Cached result — return immediately
if (data.cached) return data;
// Poll for results
while (true) {
await new Promise(r => setTimeout(r, 3000));
const status = await fetch(`${BASE}/url-scan/${data.job_id}`, { headers }).then(r => r.json());
if (status.status === 'succeeded') return status;
if (status.status === 'failed') throw new Error(status.error);
}
}
scanUrl('https://stripe.com').then(result => {
console.log(`Fonts: ${result.fonts_detected.length}`);
console.log(`Risk: ${result.compliance_summary.overall_risk}`);
console.log(`Score: ${result.compliance_summary.overall_score}%`);
});