API Reference

Complete reference for all ComplianceLayer API endpoints. All requests require authentication via API key unless noted otherwise. Base URL: https://api.compliancelayer.net/v1

RapidAPI: This API is also available on the RapidAPI marketplace. Same endpoints, same responses — use your RapidAPI key instead.

Authentication

Send your API key in the Authorization header using the Bearer scheme. The X-API-Key header is supported as an alternative, and a bare key in Authorization without the Bearer prefix is also accepted.

Authorization: Bearer cl_YOUR_API_KEY

# or
X-API-Key: cl_YOUR_API_KEY

A few endpoints are public and need no key: POST /scan/free, GET /verify/:report_id, GET /badge/:domain.svg, and GET /pricing/plans. Full details are in the authentication guide.

Error Shape

Every error response is a JSON object with a single detail key. For most errors detail is a string; for 422 request-validation failures it is an array of { field, message } objects. There is no error code, message, or status field in the body.

{
  "detail": "Scan job not found"
}

See the error handling guide for status-by-status behaviour, including how to distinguish a rate-limit 429 from an exhausted-quota 429.

Scanning

POST/scan

Queue a new scan job for a domain. Returns 202 Accepted with an integer job_id for polling. Most scans complete in roughly 10-30 seconds.

Request Body

ParameterTypeRequiredDescription
domainstringYesThe domain to scan (e.g., "example.com")
curl -X POST "https://api.compliancelayer.net/v1/scan" \
  -H "Authorization: Bearer cl_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"domain": "example.com"}'
POST/scan/free

Public scanner — no API key required. Runs a scan and returns a limited report synchronously (score, grade, module summaries, and top_issues). Rate limited to 5 scans per hour per IP.

curl -X POST "https://api.compliancelayer.net/v1/scan/free" \
  -H "Content-Type: application/json" \
  -d '{
    "domain": "example.com",
    "authorization": {"attested": true, "basis": "owner"}
  }'

# The authorization object is required on this endpoint. Omitting it, or
# sending "attested": false, returns 403. Basis must be one of:
# owner | written_authorization | authorized_agent
GET/scan/jobs/:job_id

Get the status of a scan job. Poll this endpoint until status is "completed", then fetch the full report.

Path Parameters

ParameterTypeDescription
job_idintegerThe job ID returned from POST /scan

Response Fields

FieldTypeDescription
job_idintegerJob identifier
statusstringqueued, running, completed, or failed
sourcestringWhere the scan originated (e.g. api, dashboard)
requested_modulesarrayThe 15 modules queued for this scan
failure_reasonstring | nullWhy the scan failed, when status=failed
resultobject | nullSummary results (only when status=completed)
curl "https://api.compliancelayer.net/v1/scan/jobs/12345" \
  -H "Authorization: Bearer cl_YOUR_API_KEY"
GET/scan/jobs/:job_id/report

Get the complete scan report: per-module results, every issue, and compliance framework mappings. Returns 409 Conflict if the scan hasn't finished yet.

curl "https://api.compliancelayer.net/v1/scan/jobs/12345/report" \
  -H "Authorization: Bearer cl_YOUR_API_KEY"

Each entry in issues — and in every module's issues array — has exactly three fields: severity, finding, and remediation. Grades are A, B, C, D, or F; there are no + or - variants.

GET/scan/recent

List your most recent scans with summary results. Takes no query parameters.

curl "https://api.compliancelayer.net/v1/scan/recent" \
  -H "Authorization: Bearer cl_YOUR_API_KEY"
GET/scan/history

List your scan history. Same response shape as /scan/recent — a scans array plus a total count.

Query Parameters

ParameterTypeDescription
limitintegerMaximum entries to return (default 50)

There is no offset, page, or cursor parameter — limit is the only control, so you cannot page beyond the most recent entries.

curl "https://api.compliancelayer.net/v1/scan/history?limit=100" \
  -H "Authorization: Bearer cl_YOUR_API_KEY"

Batch Operations

POST/batch/scan

Scan up to 50 domains in parallel and get them back ranked by risk. This is a quick 4-module assessment (DNS/email, SSL, headers, ports) rather than the full 15-module scan. Each domain consumes one scan from your monthly quota.

Request Body

ParameterTypeRequiredDescription
domainsarrayYes1-50 domains to scan
sort_bystringNorisk (worst first, default), score (best first), or domain
curl -X POST "https://api.compliancelayer.net/v1/batch/scan" \
  -H "Authorization: Bearer cl_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "domains": ["vendor1.com", "vendor2.com"],
    "sort_by": "risk"
  }'
POST/batch/compare

Compare 2-5 domains side by side. Returns ranked results with a winner, the score gap, and a per-module comparison. Also a 4-module assessment, and also 1 scan of quota per domain.

Request Body

ParameterTypeRequiredDescription
domainsarrayYes2-5 domains to compare

Reports & PDF

GET/compliance/reports/:job_id/pdf

Generate a PDF report for a completed scan. Returns a PDF file with executive summary, module scores, findings, and compliance framework mappings. Available on every plan, including Free — exports are bounded only by your scan quota, since a report can only be generated for a scan you have already run.

Path Parameters

ParameterTypeDescription
job_idintegerThe completed scan job ID
# Download PDF report
curl "https://api.compliancelayer.net/v1/compliance/reports/12345/pdf" \
  -H "Authorization: Bearer cl_YOUR_API_KEY" \
  --output report.pdf

The PDF includes:

  • Cover page with domain, grade, scan date, and QR verification code
  • Executive summary with issue distribution and priority recommendations
  • Module-by-module score breakdown (SSL, DNS, headers, ports, etc.)
  • Detailed findings per module
  • Compliance framework mapping (SOC 2, PCI DSS, HIPAA, NIST CSF, ISO 27001, CIS Controls v8)

Report Verification

GET/verify/:report_id

Verify the authenticity of a ComplianceLayer PDF report. Public endpoint — no authentication required. Used by the QR code embedded in every PDF to let recipients confirm the report is genuine. Rate limited to 20 requests per minute per IP.

Path Parameters

ParameterTypeDescription
report_idstringThe report ID printed on the PDF. Format CL-XXXXXXXX — the literal prefix CL- followed by 8 uppercase letters and digits.
# Public endpoint - no API key required
curl "https://api.compliancelayer.net/v1/verify/CL-7K2M9XQ4"

A malformed report ID returns the same 404 as an unknown one, so the ID format isn't leaked. There is no valid boolean in the response — a 200 means the report is genuine, a 404 means it isn't.

Badges

GET/badge/:domain.svg

Public SVG security badge for a domain, suitable for embedding in a README or website. No authentication required. Badges are opt-in: the endpoint serves only domains whose owner has published a badge, and returns 404 otherwise. The default rendering is the ComplianceLayer card; the optional style query parameter accepts flat for a compact shields-style strip.

curl "https://api.compliancelayer.net/v1/badge/example.com.svg?style=flat"
GET/badge/:domain.json

Badge data as JSON (domain, grade, score, source). Unlike the SVG variant this endpoint requires authentication, and it answers only for domains monitored by your own account. The grade and score are read from the domain's last completed scan.

curl "https://api.compliancelayer.net/v1/badge/example.com.json" \
  -H "Authorization: Bearer cl_YOUR_API_KEY"

Domain Monitoring

GET/domains

List all monitored domains for your account, along with how many of your plan's domain slots are in use.

curl "https://api.compliancelayer.net/v1/domains" \
  -H "Authorization: Bearer cl_YOUR_API_KEY"
POST/domains

Add a domain to continuous monitoring with scheduled scans.

Request Body

ParameterTypeRequiredDescription
domainstringYesThe domain to monitor
scan_frequencystringNohourly, daily, or weekly (default: daily). Anything else returns 400.
alert_on_score_dropbooleanNoWhether to raise an alert when the score falls (default: true)
alert_thresholdintegerNoScore drop that triggers an alert (default: 10)
curl -X POST "https://api.compliancelayer.net/v1/domains" \
  -H "Authorization: Bearer cl_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "domain": "example.com",
    "scan_frequency": "daily",
    "alert_on_score_drop": true,
    "alert_threshold": 10
  }'
PATCH/domains/:domain_id/badge

Publish or unpublish the public security badge for a monitored domain. Badges are opt-in: until published, GET /badge/:domain.svg returns 404 for the domain. See Security Badges.

curl -X PATCH "https://api.compliancelayer.net/v1/domains/42/badge" \
  -H "Authorization: Bearer cl_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"badge_enabled": true}'
DELETE/domains/:domain_id

Remove a domain from monitoring. Stops all scheduled scans. domain_id is the integer id from GET /domains.

POST/domains/:domain_id/scan

Trigger an immediate scan for a monitored domain, outside its regular schedule. Consumes one scan from your monthly quota.

GET/domains/alerts

List alerts for monitored domains (score drops, critical findings, certificate expiry, config changes).

Query Parameters

ParameterTypeDescription
unread_onlybooleanReturn only unread alerts (default: false)
limitintegerMaximum alerts to return (default: 50)
severitystringFilter by severity
alert_typestringFilter by alert type (e.g. critical_issue)
domain_idintegerFilter to a single monitored domain
This endpoint returns a bare JSON array, not an object with an alerts key. Index into the response directly.
curl "https://api.compliancelayer.net/v1/domains/alerts?unread_only=true&limit=20" \
  -H "Authorization: Bearer cl_YOUR_API_KEY"
POST/domains/alerts/:alert_id/read

Mark a single alert as read. alert_id is an integer.

POST/domains/alerts/mark-all-read

Mark every alert on the account as read.

DELETE/domains/alerts/:alert_id

Delete an alert.

GET/domains/alerts/stats

Alert counts for the account: total, unread, by_severity, and by_type.

Settings

GET/settings/alert-preferences

Get which alert types are enabled: score_drop, critical_issue, cert_expiry, config_change.

PUT/settings/alert-preferences

Update alert preferences. Body takes the same four booleans, each defaulting to true.

curl -X PUT "https://api.compliancelayer.net/v1/settings/alert-preferences" \
  -H "Authorization: Bearer cl_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "score_drop": true,
    "critical_issue": true,
    "cert_expiry": true,
    "config_change": false
  }'

Webhooks

Available on all plans. Free accounts are limited to 1 active endpoint; paid plans get up to 5. Everything else — signature verification, retries, delivery history, and the event catalog — is the same on every tier. See the webhooks guide for payload formats and signature verification.
GET/webhooks

List your webhook endpoints.

POST/webhooks

Create a webhook endpoint. Maximum 1 active endpoint on Free, 5 on paid plans.

Request Body

ParameterTypeRequiredDescription
urlstringYesHTTPS URL to receive webhooks
enabled_eventsarrayYesEvent types to subscribe to — at least one. Note the field is enabled_events, not events.
descriptionstringNoOptional label, up to 255 characters

The response includes the generated signing secret along with id, is_active, consecutive_failures, and delivery timestamps.

GET/webhooks/:endpoint_id

Get a single webhook endpoint. endpoint_id is an integer.

PATCH/webhooks/:endpoint_id

Update a webhook endpoint. All fields optional: url, description, enabled_events, is_active.

DELETE/webhooks/:endpoint_id

Delete a webhook endpoint.

POST/webhooks/:endpoint_id/test

Send a test event to the endpoint. Optional body field event_type (default scan.completed); an unrecognized value returns 400.

GET/webhooks/:endpoint_id/deliveries

Recent delivery attempts for an endpoint. Optional limit query parameter (default 50).

GET/webhooks/events/types

List the event types you can subscribe to.

GET/webhooks/stats/summary

Delivery success and failure counts across your endpoints. Optional hours query parameter (default 24).

Authentication Endpoints

POST/auth/signup

Create a new account. The response includes your api_key directly, so you can scan immediately without visiting the dashboard.

Request Body

ParameterTypeRequired
emailstringYes
passwordstringYes (min 12 chars)
POST/auth/login

Authenticate with email and password. Returns access_token, token_type, expires_in (86400 seconds), and csrf_token — no user object.

GET/auth/me

Get the current account: id, email, plan, api_key, scans_this_month, scan_limit, scans_remaining, domain_limit, and subscription status.

POST/auth/api-key/regenerate

Issue a new API key. There is one key per account and no create, list, or revoke operation — regenerating invalidates the previous key instantly, with no overlap window.

POST/auth/logout

Invalidate the current session. Does not affect your API key.

POST/auth/password/change

Change the password for the signed-in account.

POST/auth/reset-password

Complete a password reset using a reset token and a new_password of at least 12 characters.

Usage

GET/usage/summary

Usage totals for a period. Optional start_date and end_date query parameters in YYYY-MM-DD form.

GET/usage/limits

Your plan's limits and current consumption, including whether you can still make requests and run scans right now.

GET/usage/history

Month-by-month usage history. Optional months query parameter (default 6).

GET/usage/by-endpoint

Request counts broken down per endpoint. Optional days query parameter (default 30).

Billing

POST/billing/checkout

Create a Stripe checkout session to start a subscription.

Request Body

ParameterTypeRequiredDescription
planstringYesOne of free, starter, professional, msp, enterprise
success_urlstringYesWhere Stripe redirects after a completed checkout
cancel_urlstringYesWhere Stripe redirects if checkout is abandoned
yearlybooleanNoBill annually instead of monthly (default: false)
curl -X POST "https://api.compliancelayer.net/v1/billing/checkout" \
  -H "Authorization: Bearer cl_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "plan": "professional",
    "success_url": "https://yourapp.com/billing/success",
    "cancel_url": "https://yourapp.com/billing/cancel",
    "yearly": false
  }'

Omitting success_url or cancel_url returns 422 — both are required.

POST/billing/portal

Create a Stripe customer portal session to manage an existing subscription.

GET/billing/subscription

Current subscription state: plan, status, scans_this_month, scan_limit, and domain_limit.

GET/pricing/plans

Public list of plans with pricing, scan allowances, rate limits, and feature flags. No authentication required.

Response Codes

CodeStatusDescription
200OKRequest succeeded
202AcceptedScan queued — the success status for POST /scan
400Bad RequestSemantically invalid request (unscannable domain, bad enum value, duplicate resource). Missing or mistyped fields return 422 instead.
401UnauthorizedMissing or invalid API key
403ForbiddenAccount disabled, subscription inactive, or feature gated to a higher plan
404Not FoundResource not found
405Method Not AllowedPath exists but not for this HTTP method
409ConflictReport requested before the scan completed
422Unprocessable EntityRequest validation failed — detail is an array of field errors
429Too Many RequestsRate limit exceeded, or monthly scan quota exhausted
500Internal Server ErrorServer error (contact support)