Developers
Developer API
Programmatic access to your XenonFlare workspace for integrations, CI pipelines, and internal tools.
https://api.xenonflare.com/api/v1Plan: Starter or Growth required. Manage keys in the web app under Developer API in the sidebar.
Keys: Up to 5 active keys per organization.
Quickstart
Three lines to your first API call
Authenticate with a Bearer key from Developer API in the app sidebar (Starter or Growth). 1000 reads/hr and 60 writes/hr per key · 500 org writes/day · up to 5 active keys.
curl -H "Authorization: Bearer xf_live_xxxxxxxx" \ https://api.xenonflare.com/api/v1/properties
Base URL: https://api.xenonflare.com/api/v1 · Rate limits · All endpoints · SEO automation API
Overview
The Developer API is organization-scoped. Each API key belongs to one workspace and carries explicit permission scopes. All authenticated routes return JSON with a consistent envelope and include a requestId in meta for support.
- Read endpoints list properties, jobs, organization details, and usage.
- Write endpoints create properties and queue SEO scans or crawls.
- Keys use the format
xf_live_...(live) orxf_test_...(sandbox) and can be revoked instantly from the app.
Authentication
Send your API key as a Bearer token in the Authorization header. Create keys in the web app — they are shown once at creation; store them securely.
curl -H "Authorization: Bearer xf_live_xxxxxxxx" \ https://api.xenonflare.com/api/v1/properties
Revoked or invalid keys receive 401 with error.code: "api_key_invalid".
Test keys (sandbox)
Choose Test when creating a key to get an xf_test_… sandbox credential. Test keys read real workspace data but write endpoints return mock responses with no side effects — ideal for CI pipelines and integrator onboarding. Writes include the X-Developer-Api-Mode: test response header.
Agencies and portfolio monitoring
Agencies on Growth run one workspace with many client properties, then automate nightly POST /scans/batch, webhook alerts, and CSV activity exports for client reporting. Scoped keys let you separate read-only dashboards from automation that queues crawls. See the agency portfolio guide and SEO automation API landing for positioning and integration patterns.
Request ID
Send an optional X-Request-Id header on any authenticated request. When provided, the same value is echoed in meta.requestId on success and error responses — useful when contacting support or correlating logs on your side.
curl -H "Authorization: Bearer xf_live_xxxxxxxx" \ -H "X-Request-Id: deploy-2026-06-07-001" \ https://api.xenonflare.com/api/v1/organization
Scopes
When creating a key, select only the scopes your integration needs.
| Scope | Access |
|---|---|
org:read | Organization overview |
properties:read | List and read website properties |
properties:write | Create new properties |
jobs:read | List and read scan/crawl jobs |
jobs:write | Queue scans and crawls |
usage:read | Usage totals and plan limits |
reports:read | List and read shared audit reports |
gsc:read | Read cached Google Search Console snapshots (GET /properties/:id/gsc, GET /organization/gsc). Connect GSC in the web app first. Field reference. |
gsc:write | Trigger GSC snapshot refresh (POST /properties/:id/gsc/sync) |
webhooks:read | List outbound webhook endpoints |
webhooks:write | Create, update, and delete webhook endpoints |
See also the nightly crawl guide, CI pipeline guide, and agency portfolio guide for automation patterns.
Endpoints
System
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /health | None | API reachability — returns status, version, timestamp, and a statusPage URL (status.xenonflare.com) |
Organization
| Method | Path | Scope | Description |
|---|---|---|---|
| GET | /organization | org:read | Workspace summary and usage totals |
Properties
| Method | Path | Scope | Description |
|---|---|---|---|
| GET | /properties | properties:read | Paginated list of website properties |
| POST | /properties | properties:write | Create property — body: { "url", "name?" } |
| GET | /properties/:id | properties:read | Single property detail — optional ?include=gsc,lastScan |
| GET | /properties/:id/issues | properties:read | Paginated SEO issues with lifecycle summary |
| POST | /properties/:id/scans | jobs:write | Queue an SEO scan job (seo-scan) |
| POST | /properties/:id/crawls | jobs:write | Queue a crawl (same job type as scans) |
Optional scan/crawl body: { "maxPages": number, "maxDepth": number }. Successful queue responses return 202 Accepted. Use ?include=gsc,lastScan on property list/detail to embed GSC summary or last scan metadata without extra round trips.
Jobs
| Method | Path | Scope | Description |
|---|---|---|---|
| GET | /jobs | jobs:read | Paginated list of jobs |
| GET | /jobs/:id | jobs:read | Job status, stable result payload, and recent logs |
| POST | /jobs/:id/cancel | jobs:write | Cancel a pending or processing job |
| POST | /scans/batch | jobs:write | Queue up to 25 scans — per-property success/error in results |
Optional filters on GET /jobs: status (pending, processing, completed, failed, cancelled), propertyId, and type (for example seo-scan).
Completed scan jobs expose a stable result object on GET /jobs/:id:
{
"scanId": "507f1f77bcf86cd799439016",
"score": 82,
"issuesCount": 14,
"pagesScanned": 48,
"pagesFailed": 0,
"pagesSkipped": 2,
"stopReason": "max_pages",
"maxPages": 50,
"urlsAttempted": 52,
"categoryScores": { "technical": 90, "content": 78 },
"shareUrl": null
}GET https://api.xenonflare.com/api/v1/jobs?status=completed&propertyId=PROPERTY_ID&type=seo-scan
Usage
| Method | Path | Scope | Description |
|---|---|---|---|
| GET | /usage | usage:read | Current usage against plan limits |
| GET | /limits | usage:read | Plan limits for the workspace |
| GET | /rate-limits | usage:read | Live remaining read/write and org daily write counters for this API key |
Webhooks
| Method | Path | Scope | Description |
|---|---|---|---|
| GET | /webhooks | webhooks:read | List outbound webhook endpoints |
| POST | /webhooks | webhooks:write | Create endpoint — signingSecret returned once |
| PATCH | /webhooks/:id | webhooks:write | Update name, URL, events, or enabled flag |
| DELETE | /webhooks/:id | webhooks:write | Remove webhook endpoint |
| POST | /webhooks/:id/test | webhooks:write | Send a signed sample payload (test: true in body) — also available as Test in the Developer API webhooks tab |
Events: job.completed, job.failed, job.cancelled. Verify deliveries with the X-XenonFlare-Signature header (HMAC SHA-256 over {timestamp}.{body}). Test deliveries use the same headers with a synthetic job and test: true in the JSON body.
Reports
| Method | Path | Scope | Description |
|---|---|---|---|
| GET | /reports | reports:read | List active shared audit reports (non-expired links) |
| GET | /reports/:token | reports:read | Report metadata and public URL for a share token |
Reports are created in the web app when you share an audit. Each item includes a publicUrl pointing to the read-only report page on xenonflare.com. Use reports:read on keys that should list share links but not queue scans — common for client-facing dashboards and monthly reporting pipelines.
Example: list shared reports
curl -H "Authorization: Bearer xf_live_..." \ https://api.xenonflare.com/api/v1/reports?limit=20
{
"data": {
"reports": [
{
"token": "abc123sharetoken",
"propertyId": "507f1f77bcf86cd799439012",
"propertyName": "example.com",
"propertyUrl": "https://example.com",
"scanId": "507f1f77bcf86cd799439013",
"expiresAt": "2026-07-07T12:00:00.000Z",
"viewCount": 4,
"createdAt": "2026-06-07T12:00:00.000Z",
"publicUrl": "https://xenonflare.com/reports/abc123sharetoken"
}
]
},
"meta": {
"requestId": "req_reports_001",
"hasMore": false,
"nextCursor": null
}
}Fetch a single report with GET /reports/:token. Related: Site audit API, agency portfolio guide.
Search Console
| Method | Path | Scope | Description |
|---|---|---|---|
| GET | /organization/gsc | gsc:read | Portfolio summary — linked properties, 28-day clicks and impressions totals |
| GET | /properties/:id/gsc | gsc:read | Cached snapshot: queries, pages, daily series, crawl correlation (null when not linked) |
| GET | /properties/:id/gsc/overview | gsc:read | Connection status and 28-day totals only |
| GET | /properties/:id/gsc/queries | gsc:read | Paginated top queries from cached snapshot |
| GET | /properties/:id/gsc/pages | gsc:read | Paginated top pages from cached snapshot |
| POST | /properties/:id/gsc/sync | gsc:write | Trigger a live GSC refresh (uses org OAuth from the web app) |
GSC OAuth connect runs in the web app. Most read endpoints use stored MongoDB snapshots; POST …/gsc/sync calls Google with the linked org token.
Response format
Successful responses wrap data in a consistent envelope:
{
"data": { },
"meta": {
"requestId": "...",
"hasMore": false,
"nextCursor": null
}
}Errors use the same meta.requestId with an error object:
{
"error": {
"code": "plan_required",
"message": "..."
},
"meta": { "requestId": "..." }
}Examples
GET /organization
{
"data": {
"organization": {
"id": "507f1f77bcf86cd799439011",
"name": "Acme Marketing",
"plan": "starter"
},
"usage": { "plan": "starter", "periodLabel": "Jun 2026" },
"totals": { "properties": 3, "activeJobs": 1 }
},
"meta": { "requestId": "req_abc123" }
}GET /properties
{
"data": {
"properties": [
{
"id": "507f1f77bcf86cd799439012",
"name": "example.com",
"url": "https://example.com",
"verified": true,
"createdAt": "2026-06-01T10:00:00.000Z"
}
]
},
"meta": {
"requestId": "req_abc123",
"hasMore": false,
"nextCursor": null
}
}POST /properties/:id/scans (202)
{
"data": {
"job": {
"id": "507f1f77bcf86cd799439014",
"status": "pending",
"type": "seo-scan",
"propertyId": "507f1f77bcf86cd799439012",
"createdAt": "2026-06-07T12:00:00.000Z"
},
"crawlTier": "verified",
"effectiveLimits": { "maxPages": 500, "maxDepth": 8 },
"message": "Website SEO scan queued."
},
"meta": { "requestId": "req_scan_001" }
}GET /jobs/:id
{
"data": {
"job": {
"id": "507f1f77bcf86cd799439014",
"type": "seo-scan",
"status": "completed",
"progress": 100,
"propertyId": "507f1f77bcf86cd799439012",
"propertyName": "example.com",
"createdAt": "2026-06-07T12:00:00.000Z",
"completedAt": "2026-06-07T12:05:12.000Z",
"error": null
}
},
"meta": { "requestId": "req_job_poll" }
}Error (403 plan_required)
{
"error": {
"code": "plan_required",
"message": "Website limit reached for this workspace."
},
"meta": { "requestId": "req_limit_001" }
}Pagination
List endpoints accept limit (max 100, default 40) and cursor. When more results exist, meta.hasMore is true and meta.nextCursor contains an opaque token for the next page.
GET https://api.xenonflare.com/api/v1/properties?limit=40&cursor=opaque_token
Idempotency
Write endpoints (POST) accept an optional Idempotency-Key header (max 128 characters). Repeating the same key within 24 hours returns the original successful response without duplicating side effects — useful for retries in CI or webhook handlers.
curl -X POST \ -H "Authorization: Bearer xf_live_..." \ -H "Idempotency-Key: scan-2026-06-07-example-com" \ https://api.xenonflare.com/api/v1/properties/PROPERTY_ID/scans
Full guide: Idempotency for write requests (TTL, replay rules, CI key patterns, retry matrix).
Rate limits
Two layers apply: API rate limits (per key / per org) and plan quotas (scans, websites, crawl pages). Plan quotas are enforced on write endpoints and return 403 plan_required; API rate limits return 429 rate_limit.
| Limit | Default | Scope |
|---|---|---|
| Read requests per API key | 1,000 / hour | API rate limit |
| Write requests per API key | 60 / hour | API rate limit |
| Write requests per organization | 500 / day | API rate limit (safety net) |
| Active API keys per organization | 5 | Key cap |
| Scans / websites / crawl pages | Plan-dependent | Plan quota — see GET /limits |
Headers and live counters
Successful responses include X-Developer-Api-RateLimit-read-* or X-Developer-Api-RateLimit-write-* headers (Limit, Remaining, Reset). For programmatic backoff, call GET /rate-limits (usage:read):
curl -H "Authorization: Bearer xf_live_..." \ https://api.xenonflare.com/api/v1/rate-limits
{
"data": {
"rateLimits": {
"read": { "limit": 1000, "remaining": 987, "used": 13, "resetAt": "2026-06-07T13:00:00.000Z" },
"write": { "limit": 60, "remaining": 58, "used": 2, "resetAt": "2026-06-07T13:00:00.000Z" },
"orgWriteDaily": { "limit": 500, "remaining": 495, "used": 5, "resetAt": "2026-06-08T00:00:00.000Z" }
}
}
}Static plan caps (including documented API limits) are on GET /limits under data.developerApi. When exceeded, the API returns 429 with a Retry-After header (seconds until the window resets):
HTTP/1.1 429 Too Many Requests
Retry-After: 1847
{
"error": { "code": "rate_limit", "message": "Rate limit exceeded — try again later" },
"meta": { "requestId": "req_rl_001" }
}For incident and uptime information, see status.xenonflare.com. AI assistants can use the llms.txt index for a concise map of endpoints and guides.
Step-by-step
- Sign in at app.xenonflare.com on a Starter or Growth plan.
- Open Developer API in the sidebar and create a key with
properties:readandjobs:writeas needed. - List properties, queue a scan, and poll job status:
# List properties curl -H "Authorization: Bearer xf_live_..." \ https://api.xenonflare.com/api/v1/properties # Queue a scan curl -X POST \ -H "Authorization: Bearer xf_live_..." \ https://api.xenonflare.com/api/v1/properties/PROPERTY_ID/scans # Poll job status curl -H "Authorization: Bearer xf_live_..." \ https://api.xenonflare.com/api/v1/jobs/JOB_ID
Error catalog
All errors use { error: { code, message }, meta: { requestId } }.
| Code | HTTP | When | What to do |
|---|---|---|---|
api_key_invalid | 401 | Missing, malformed, or revoked Bearer token | Check header format; create or rotate key in Developer settings |
unauthorized | 401 | Developer API disabled or auth rejected | Verify plan and that Developer API is enabled for the workspace |
insufficient_scope | 403 | Key lacks required scope for the route | Create a key with the scope listed on the endpoint, or rotate with broader scopes |
forbidden | 403 | Generic access denied (non-scope) | Confirm org membership and endpoint access rules |
plan_required | 403 | Free plan, or monthly scan/website quota exhausted | Upgrade plan or wait for billing period reset; check GET /usage |
rate_limit | 429 | API read/write or org daily write cap exceeded | Backoff until reset; use GET /rate-limits or rate-limit headers |
not_found | 404 | Property, job, webhook, or report not in this org | Verify ID belongs to the keyed organization |
validation_error | 400 | Invalid body, query param, or business rule (e.g. cancel completed job) | Fix request per message; use new idempotency key if body changed |
internal_error | 500 | Unexpected server failure | Retry with backoff; contact support with meta.requestId |
SDK & code generation
Generate a typed client from the OpenAPI spec with OpenAPI Generator. Replace the output directory with your project path.
TypeScript (fetch)
npx @openapitools/openapi-generator-cli generate \ -i https://xenonflare.com/openapi/developer-v1.yaml \ -g typescript-fetch \ -o ./src/generated/xenonflare-api
Python
npx @openapitools/openapi-generator-cli generate \ -i https://xenonflare.com/openapi/developer-v1.yaml \ -g python \ -o ./xenonflare_api_client
Pass your key on every request: Authorization: Bearer xf_live_…. For local development, point -i at http://localhost:4000/openapi/developer-v1.yaml or the copy in this repo.
OpenAPI
Machine-readable specification for code generation and API clients: developer-v1.yaml (OpenAPI 3.1). Download from the quickstart panel above or import into your preferred API client.
Developer API