API Endpoints
Complete reference for all ScriptAttest API endpoints with request/response schemas and examples.
Note: All endpoints require Enterprise plan and API key authentication. See API Overview for authentication details.
Sites
Manage sites in your organization.
List Sites
GET /api/sites?limit=50 Returns a list of all sites in your organization.
Query Parameters
| Parameter | Type | Description |
|---|---|---|
limit | integer | Number of sites to return (default: 50, max: 100) |
Response
{
"sites": [
{
"id": "uuid",
"org_id": "uuid",
"domain": "example.com",
"name": "My Site",
"status": "pending" | "active",
"report_uri_token": "hex_string",
"created_at": 1234567890,
"recent_violations": 5,
"scan_count": 12
}
]
} Create Site
POST /api/sites Add a new site to monitor.
Request Body
{
"domain": "example.com",
"name": "My Example Site" // optional
} Response (201 Created)
{
"site": {
"id": "uuid",
"domain": "example.com",
"name": "My Example Site",
"status": "pending",
"reportUriToken": "hex_string"
}
} Errors
400- Invalid domain format or missing domain403- Site limit reached (upgrade required)409- Domain already exists for this organization
Get Site
GET /api/sites/:id Get detailed information for a specific site, including latest scan status and source counts.
Response
{
"site": {
"id": "uuid",
"domain": "example.com",
"name": "My Site",
"status": "active",
"report_uri_token": "hex_string",
"hasPolicy": true,
"created_at": 1234567890,
"updated_at": 1234567890
},
"latestScan": {
"id": "uuid",
"status": "completed",
"violationCount": 0,
"externalSourceCount": 15,
"createdAt": 1234567890,
"completedAt": 1234567900
},
"sources": {
"total": 20,
"approved": 15,
"pending": 5
}
} Update Site
PATCH /api/sites/:id Update site settings. All fields are optional.
Request Body
{
"name": "Updated Site Name",
"autoApproveFirstParty": true,
"strictScripts": true,
"strictStyles": false,
"emailAlertsEnabled": true
} Response
{
"success": true
} Delete Site
DELETE /api/sites/:id Delete a site and all associated data (scans, policies, sources, schedules, violations).
Response
{
"success": true
} Scans
Trigger and monitor CSP discovery and validation scans.
Trigger Discovery Scan
POST /api/sites/:id/scan/discover Start a discovery scan to find all third-party resources (scripts, stylesheets, fonts, images, etc.) on all enabled pages.
Response
{
"batchId": "uuid",
"status": "queued",
"message": "Discovery scan started"
} Notes
- Scans all enabled pages for the site
- Results are merged across all pages
- Use
discover-statusendpoint to poll for completion
Get Discovery Scan Status
GET /api/sites/:id/scan/discover-status?batchId=:batchId Check the status of a discovery scan.
Response
{
"status": "queued" | "running" | "completed" | "failed",
"progress": {
"pagesScanned": 5,
"totalPages": 10,
"sourcesFound": 25
},
"results": {
"externalSources": 25,
"violations": 0
}
} Trigger Validation Scan
POST /api/sites/:id/scan/validate Validate your current CSP policy against all enabled pages. Requires Pro+ plan.
Response
{
"batchId": "uuid",
"status": "queued",
"message": "Validation scan started"
} Errors
403- Validation scans require Pro+ plan400- No policy exists for this site
Get Validation Scan Status
GET /api/sites/:id/scan/validate-status?batchId=:batchId Check the status of a validation scan.
Response
{
"status": "queued" | "running" | "completed" | "failed",
"progress": {
"pagesScanned": 3,
"totalPages": 5
},
"results": {
"violations": 2,
"pagesWithViolations": 1
}
} Script Attestation
Run behavioral integrity scans to detect script changes and suspicious activity. Requires Pro+ plan.
Start Attestation
POST /api/sites/:id/attest Start a script attestation scan to verify script integrity and detect behavioral changes.
Response
{
"scanId": "uuid",
"status": "queued",
"message": "Attestation scan started"
} Errors
403- ScriptAttest requires Pro+ plan
Get Attestation Status
GET /api/sites/:id/attest/status?scanId=:scanId Check the status of an attestation scan.
Response
{
"status": "queued" | "running" | "completed" | "failed",
"scanId": "uuid",
"results": {
"scriptsAnalyzed": 15,
"suspiciousActivity": 0,
"baselineMatches": true
}
} Set Baseline
POST /api/sites/:id/attest/set-baseline Set the current attestation results as the baseline for future comparisons.
Response
{
"success": true,
"message": "Baseline set successfully"
} Policies
Generate and manage Content Security Policies.
Generate Policy
POST /api/sites/:id/policies/generate Generate a new CSP policy based on approved sources. Uses site's strictScripts and strictStyles settings by default.
Request Body (all fields optional)
{
"strictScripts": true, // Override site setting
"strictStyles": false, // Override site setting
"reportOnly": false, // Generate report-only policy
"includeReportUri": true, // Include report-uri directive
"customPolicy": "..." // Save a manually edited policy
} Response
{
"success": true,
"policy": {
"id": "uuid",
"version": 2,
"policy": "default-src 'self'; script-src 'self' 'sha256-...'; ...",
"status": "active" | "testing" | "deployed",
"reportOnly": false,
"tier": "baseline" | "hardened" | "app-enforced",
"tierDescription": "Security tier description",
"warnings": [
"Third-party script origins present: cdn.example.com - supply chain risk"
],
"thirdPartyScriptOrigins": ["cdn.example.com"],
"features": {
"hashBasedScripts": true,
"scriptSrcElem": true,
"unsafeInlineScripts": false,
"unsafeInlineStyles": false,
"upgradeInsecureRequests": true
}
}
} Notes
- Policy is generated from all approved sources
- If
customPolicyis provided, it's saved directly (manual edit mode) - Policy version is auto-incremented
- New policy becomes the site's
current_policy_id
Update Policy Status
POST /api/sites/:id/policies/:policyId/status Change a policy's status (e.g., move to testing or deploy).
Request Body
{
"status": "active" | "testing" | "deployed"
} Response
{
"success": true
} Notes
active- Default state for newly created policiestesting- Policy is being tested before deploymentdeployed- Policy is live (only one policy can be deployed at a time)
Restore Policy
POST /api/sites/:id/policies/restore Restore a previous policy version by creating a new version from it.
Request Body
{
"policyId": "uuid"
} Response
{
"success": true,
"message": "Created v3 from v1",
"newPolicyId": "uuid",
"newVersion": 3,
"restoredFromVersion": 1
} Sources
Manage external sources (scripts, stylesheets, fonts, etc.) discovered during scans.
List Sources
GET /api/sites/:id/sources?status=pending&type=script List all discovered sources with optional filters.
Query Parameters
| Parameter | Type | Description |
|---|---|---|
status | string | Filter by status: pending, approved, rejected |
type | string | Filter by type: script, style, font, img, connect, etc. |
Response
{
"sources": [
{
"id": "uuid",
"site_id": "uuid",
"url": "https://cdn.example.com/script.js",
"domain": "cdn.example.com",
"type": "script",
"status": "pending",
"content_hash": "sha256-...",
"first_seen_at": 1234567890,
"last_seen_at": 1234567890
}
],
"count": 25
} Approve Domain
POST /api/sites/:id/sources/approve-domain Approve all sources from a specific domain (optionally filtered by type).
Request Body
{
"domain": "cdn.example.com",
"type": "script" // optional: approve only specific type
} Response
{
"success": true,
"approvedCount": 5
} Approve Hash
POST /api/sites/:id/sources/approve-hash Approve a source by its content hash (for inline scripts/styles).
Request Body
{
"hash": "sha256-abc123...",
"type": "script" | "style"
} Response
{
"success": true
} Approve Unsafe
POST /api/sites/:id/sources/approve-unsafe Approve unsafe-inline or unsafe-eval for a specific directive.
Request Body
{
"directive": "script-src" | "style-src",
"value": "unsafe-inline" | "unsafe-eval"
} Response
{
"success": true
} Reject Domain
POST /api/sites/:id/sources/reject-domain Reject all sources from a specific domain.
Request Body
{
"domain": "malicious.example.com"
} Response
{
"success": true,
"rejectedCount": 3
} Approve Source
POST /api/sites/:id/sources/:sourceId/approve Approve a specific source by ID.
Response
{
"success": true
} Reject Source
POST /api/sites/:id/sources/:sourceId/reject Reject a specific source by ID.
Response
{
"success": true
} Pages
Manage pages to scan for a site.
List Pages
GET /api/sites/:id/pages List all pages configured for a site.
Response
{
"pages": [
{
"id": "uuid",
"site_id": "uuid",
"path": "/",
"label": "Homepage",
"enabled": 1,
"created_at": 1234567890,
"last_scanned_at": 1234567890
}
]
} Add Page
POST /api/sites/:id/pages Add a new page to scan.
Request Body
{
"path": "/about",
"label": "About Page" // optional
} Response (201 Created)
{
"page": {
"id": "uuid",
"site_id": "uuid",
"path": "/about",
"label": "About Page",
"enabled": 1,
"created_at": 1234567890,
"last_scanned_at": null
},
"needsRevalidation": true,
"message": "Page added. Run validation to include this page in your CSP policy."
} Update Page
PATCH /api/sites/:id/pages/:pageId Update page settings (enable/disable, label, etc.).
Request Body
{
"enabled": false,
"label": "Updated Label"
} Response
{
"success": true
} Schedules
Create and manage scheduled scans. Requires Pro+ plan.
List Schedules
GET /api/sites/:id/schedules List all scheduled scans for a site.
Response
{
"schedules": [
{
"id": "uuid",
"site_id": "uuid",
"name": "Daily Validation",
"type": "csp_validation",
"frequency": "daily",
"cron_expression": null,
"timezone": "UTC",
"enabled": 1,
"next_run_at": 1234567890,
"created_at": 1234567890
}
],
"count": 2
} Create Schedule
POST /api/sites/:id/schedules Create a new scheduled scan.
Request Body
{
"name": "Daily Validation Scan",
"type": "csp_validation" | "csp_discovery" | "attestation",
"frequency": "daily" | "weekly" | "monthly" | "custom",
"cronExpression": "0 2 * * *", // required if frequency is "custom"
"timezone": "UTC", // optional, defaults to UTC
"enabled": true, // optional, defaults to true
"options": {} // optional scan-specific options
} Response (201 Created)
{
"id": "uuid",
"nextRunAt": 1234567890,
"enabled": true
} Errors
403- Schedules require Pro+ plan400- Invalid schedule type, frequency, or missing cronExpression for custom frequency
Update Schedule
PATCH /api/sites/:id/schedules/:scheduleId Update a scheduled scan (same fields as create).
Delete Schedule
DELETE /api/sites/:id/schedules/:scheduleId Delete a scheduled scan.
Response
{
"success": true
} CSP Violation Reports
Endpoint for browsers to report CSP violations. This is automatically configured when you deploy a policy with a report-uri directive.
Report Violation
POST /api/csp/report/:token Public endpoint (no authentication required) for browsers to report CSP violations. Protected by domain validation and rate limiting.
Request Body
Browsers send CSP violation reports in the following format:
{
"csp-report": {
"document-uri": "https://example.com/page",
"blocked-uri": "https://evil.com/script.js",
"violated-directive": "script-src",
"effective-directive": "script-src",
"original-policy": "default-src 'self'; script-src 'self'",
"disposition": "enforce",
"source-file": "https://example.com/app.js",
"line-number": 42,
"column-number": 10,
"status-code": 200
}
} Response
Always returns 204 No Content (silent success) to prevent browser console errors.
Security Features
- Domain validation (checks
document-urimatches site domain) - Rate limiting (100 reports/hour per IP)
- Plan-based quotas (Free: 1000/month, Pro: 50000/month, Enterprise: unlimited)
- Free plan sites are rejected (report-uri is Pro+ feature)
- Payload size limit (10KB max)
API Keys
Manage API keys for programmatic access. Enterprise plan only.
List API Keys
GET /api/api-keys List all API keys for your organization.
Response
{
"keys": [
{
"id": "uuid",
"name": "Production API Key",
"prefix": "qs_A1B2C3D4",
"createdAt": 1234567890000,
"lastUsedAt": 1234567900000
}
],
"apiAccessEnabled": true
} Non-Enterprise Response
{
"keys": [],
"apiAccessEnabled": false,
"requiredPlan": "enterprise",
"message": "API access is only available on the Enterprise plan"
} Create API Key
POST /api/api-keys Create a new API key. The full key is only shown once - store it securely immediately.
Request Body
{
"name": "Production API Key"
} Response (201 Created)
{
"id": "uuid",
"name": "Production API Key",
"key": "qs_A1B2C3D4E5F6G7H8I9J0K1L2M3N4O5P6Q7R8S9T0U1V2W3X4Y5Z6",
"prefix": "qs_A1B2C3D4",
"createdAt": 1234567890000
} Important
The full API key is only returned once when created. If you lose it, you must delete and create a new key.
Errors
400- Name is required403- API access requires Enterprise plan
Delete API Key
DELETE /api/api-keys/:id Delete an API key. This action cannot be undone.
Response
{
"success": true
} Example: Complete Workflow
Here's a complete example of using the API to set up CSP for a new site:
# 1. Create a site
curl -X POST https://scriptattest.com/api/sites \
-H "Authorization: Bearer qs_your_api_key" \
-H "Content-Type: application/json" \
-d '{"domain": "example.com", "name": "My Site"}'
# 2. Add pages to scan
curl -X POST https://scriptattest.com/api/sites/SITE_ID/pages \
-H "Authorization: Bearer qs_your_api_key" \
-H "Content-Type: application/json" \
-d '{"path": "/", "label": "Homepage"}'
# 3. Run discovery scan
curl -X POST https://scriptattest.com/api/sites/SITE_ID/scan/discover \
-H "Authorization: Bearer qs_your_api_key"
# 4. Poll for completion
curl -X GET "https://scriptattest.com/api/sites/SITE_ID/scan/discover-status?batchId=BATCH_ID" \
-H "Authorization: Bearer qs_your_api_key"
# 5. Approve sources
curl -X POST https://scriptattest.com/api/sites/SITE_ID/sources/approve-domain \
-H "Authorization: Bearer qs_your_api_key" \
-H "Content-Type: application/json" \
-d '{"domain": "cdn.example.com", "type": "script"}'
# 6. Generate policy
curl -X POST https://scriptattest.com/api/sites/SITE_ID/policies/generate \
-H "Authorization: Bearer qs_your_api_key" \
-H "Content-Type: application/json" \
-d '{"strictScripts": true, "strictStyles": false}'
# 7. Deploy the policy from the response to your web server