Skip to content

Domain Analyzer

Unified Metrics Platform

Domain Metrics API /v1

External REST API for creating scrape jobs and receiving results via callbacks. Authentication uses Bearer API keys; every endpoint is owner-scoped to the calling key.

Authentication

Every /v1 request requires an API key with at least one scope. Keys are scoped to a single tenant — you only see your own jobs and results.

Authorization: Bearer dm_jobs_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Equivalent header: X-API-Key: dm_jobs_...

Scopes

ScopeAllows
jobs:createPOST /v1/jobs · DELETE /v1/jobs/<id>
jobs:readGET /v1/jobs · GET /v1/jobs/<id> · GET /v1/jobs/<id>/results
keys:adminPOST /v1/keys · DELETE /v1/keys/<id>
keys:readGET /v1/keys (admin sees all; non-admin sees own row)

Endpoints

Create a job

POST /v1/jobs
Authorization: Bearer dm_jobs_...
Content-Type: application/json

{
  "domains": ["bnt.bg", "btv.bg", "nova.bg"],
  "job_types": ["seokicks", "moz"],
  "webhook_url": "https://your-app.example.com/webhooks/domain-metrics"
}

Response (201):

{
  "job_id": "f1167536-26a6-4f5e-88f1-e10c6ec01fab",
  "status": "queued",
  "created_at": "2026-04-25T12:00:00Z",
  "webhook_secret": "wsec_xxxxxxxx..."   
}

Available job_types: seokicks, moz, ahrefs_backlinks, ahrefs_traffic, wayback, ping.

List jobs

GET /v1/jobs?limit=50&cursor=<last_seen_id>

Returns: {"jobs": [...], "next_cursor": "..."}. Keyset pagination on (created_at, id) DESC.

Job status

GET /v1/jobs/<id>

Job results

GET /v1/jobs/<id>/results

Returns one row per (domain, source). Typed columns from results_core + the JSONB raw payload from each source.

Cancel a job

DELETE /v1/jobs/<id>

Soft-cancel. Currently transitions queued/running jobs to paused; hard-cancel/cleanup planned for a follow-up.

API keys (admin)

POST /v1/keys
{ "name": "tenant-acme", "scopes": ["jobs:create", "jobs:read"] }
→ { "id": "...", "token": "dm_jobs_xxx" }   

GET /v1/keys
DELETE /v1/keys/<id>

Webhooks

If you set webhook_url when creating a job, we POST a JSON payload to that URL when the job hits a terminal status (completed or failed). Requests are signed with HMAC-SHA256 using the webhook_secret returned at creation.

Payload

POST <your_webhook_url>
Content-Type: application/json
X-DomainMetrics-Signature: sha256=<hex_hmac_of_body>

{
  "job_id": "f1167536-26a6-4f5e-88f1-e10c6ec01fab",
  "status": "completed",
  "completed_at": "2026-04-25T12:00:42Z",
  "results_url": "https://metrics.example.com/v1/jobs/f116.../results"
}

Verifying the signature (Python)

import hmac, hashlib
def verify(body: bytes, header: str, secret: str) -> bool:
    expected = "sha256=" + hmac.new(
        secret.encode(), body, hashlib.sha256
    ).hexdigest()
    return hmac.compare_digest(expected, header)

Verifying the signature (Node)

const crypto = require("crypto");
function verify(body, header, secret) {
  const expected = "sha256=" +
    crypto.createHmac("sha256", secret).update(body).digest("hex");
  return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(header));
}

Retry policy

  • 5xx / network error: retried up to 3 times with backoff 5s → 30s → 5min.
  • 4xx response: dropped, no retry. Fix your endpoint.
  • Every attempt is recorded in our internal webhook_deliveries log; ask if you need delivery history exposed via the API.

Source matrix (per scrape job)

Source Speed Bulk Returns
seokicks~1s/domainlinkpop, domainpop, ip_pop, classc_pop, 50 referring rows
moz~3s/domain10/batchDA, PA, spam score, linking domains, inbound links
ahrefs_backlinks~30s/domainDR, backlinks, ref domains, dofollow %
ahrefs_traffic~34s/domainorganic traffic, traffic value, top keywords/pages
wayback~10s/domainarchived snapshot count
pingsub-secondreachability + status code