DatIQ Help
← Back to app
For developers

DatIQ Developer API Reference

The public DatIQ HTTP API — extract, enrich, batch, and schedule from your own code.

For developers integrating DatIQ into their own software. This reference describes DatIQ's
public HTTP API — the endpoints, authentication, request parameters, and response schemas you use
to extract, enrich, batch, and schedule from your own code.

It documents only the public, outward-facing API. It intentionally does not describe DatIQ's
internal implementation. You don't need to know how DatIQ works inside to build against it — you
only need the contract below.

Availability: the public API is part of API access, included on the Business plan and above.
This reference is published ahead of general availability; treat unreleased endpoints as a preview and
pin to the versioned base URL.


Overview

  • Base URL: https://api.datiq.app/v1
  • Protocol: HTTPS only. All requests and responses are JSON (Content-Type: application/json).
  • Versioning: the major version is in the path (/v1). Breaking changes ship under a new version; additive changes do not.
  • Authentication: a secret API key sent as a bearer token (see below).

The API mirrors the extraction and monitoring core of the app: extract a page, enrich it, generate content, run a batch, run a discoverability audit, and manage schedules that watch pages for changes.

Getting intelligence out without polling. DatIQ's newer workflow surfaces — templates, bulk account lists, competitor watchlists — do not yet have public REST endpoints (see Planned endpoints at the end of this document). They are, however, already programmatically reachable in the direction most integrations want: a signal routing rule configured in the app can call your webhook whenever a watched competitor changes, an account crosses your ICP threshold, or a workflow run finishes. That is a push, so you receive events as they happen instead of polling for them. See Webhooks below for the envelope, signing and retry behaviour.


Authentication

Authenticate every request with your API key in the Authorization header:

Authorization: Bearer dq_live_xxxxxxxxxxxxxxxxxxxxxxxx
  • Create and revoke keys in Account → API keys (Business plan and above).
  • Keys are secret — use them only from your server, never in browser or mobile client code.
  • Test keys are prefixed dq_test_ and run against a sandbox that returns representative sample data without consuming quota.

Requests without a valid key return 401 Unauthorized.


Requests & conventions

  • IDs are opaque strings; do not parse them.
  • Timestamps are ISO-8601 UTC strings (e.g. 2026-06-20T13:49:26Z).
  • Pagination uses limit (default 25, max 100) and cursor. List responses return a next_cursor when more results exist.
  • Idempotency: send an Idempotency-Key header on POST requests to safely retry without creating duplicates.

Rate limits

Limits depend on your plan. Every response includes these headers:

HeaderMeaning
X-RateLimit-LimitRequests allowed in the current window.
X-RateLimit-RemainingRequests left in the current window.
X-RateLimit-ResetUnix time when the window resets.

Exceeding the limit returns 429 Too Many Requests. Back off and retry after the reset.


Endpoints

Extract a single page

POST /v1/extractions

Request body

FieldTypeRequiredDescription
urlstringyesThe public page URL to extract.
intentstringnoOne of summary (default), contacts, pricing, map, custom.
promptstringwhen intent=customPlain-English description of the field(s) to extract.
render_jsbooleannoRender JavaScript before reading the page. Default false.
curl https://api.datiq.app/v1/extractions \
  -H "Authorization: Bearer $DATIQ_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://example.com",
    "intent": "summary"
  }'

Returns an Extraction object (see schemas).

Retrieve an extraction

GET /v1/extractions/{id}

Returns the Extraction object for a previously created extraction.

List extractions

GET /v1/extractions?limit=25&cursor=...

Returns { "data": [ Extraction, ... ], "next_cursor": "..." | null }.

Delete an extraction

DELETE /v1/extractions/{id}

Returns 204 No Content.

Enrich an extraction

Run a targeted follow-up pass that adds more detail to an existing extraction.

POST /v1/extractions/{id}/enrichments
FieldTypeRequiredDescription
focusstringyesOne of contacts, leadership, social, mission, pricing.

Returns an Enrichment object.

Generate content from an extraction

POST /v1/extractions/{id}/content
FieldTypeRequiredDescription
formatstringyesOne of seo_outline, competitor_summary, social_posts.

Returns { "format": "...", "content": "..." }.

Submit a batch

Extract many URLs in one job.

POST /v1/batches
FieldTypeRequiredDescription
urlsstring[]yesList of public page URLs.
intentstringnoSame values as a single extraction. Applied to every URL.
promptstringwhen intent=customPlain-English field description.
curl https://api.datiq.app/v1/batches \
  -H "Authorization: Bearer $DATIQ_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "urls": ["https://example.com", "https://stripe.com"],
    "intent": "summary"
  }'

Returns a Batch object with status: "queued".

Get batch status & results

GET /v1/batches/{id}

Returns the Batch object. When status is completed, results holds one entry per URL (each with its own status and, on success, an embedded Extraction).

Discoverability audits

Score a page for classic search (SEO), answer engines (AEO) and generative engines (GEO), and get the prioritised fixes.

POST   /v1/audits                          # run an audit
GET    /v1/audits                          # list your audits
GET    /v1/audits/{id}                     # status and summary
GET    /v1/audits/{id}/results             # the full payload
GET    /v1/audits/{id}/report              # markdown, csv or json
POST   /v1/audits/{id}/rerun               # re-run, measured against this one
DELETE /v1/audits/{id}
GET    /v1/audits/{id}/compare/{baseline}  # what changed between two audits
GET    /v1/audits/{id}/recommendations
GET    /v1/audits/{id}/headings
GET    /v1/audits/{id}/schema
GET    /v1/audits/{id}/answers
GET    /v1/audits/{id}/entities
GET    /v1/audits/{id}/technical
POST   /v1/recommendations/{id}/accept
POST   /v1/recommendations/{id}/dismiss    # a reason is required
GET    /v1/targets                         # pages you have audited
GET    /v1/targets/{id}/history
GET    /v1/targets/{id}/trends             # time series for charting
POST   /v1/benchmarks                      # audit several URLs and compare
GET    /v1/benchmarks/{id}

Create body

FieldTypeRequiredDescription
target_urlstringyesThe page to audit.
device_profilestringnomobile (default) or desktop.
audit_profilestringnobalanced (default), seo, aeo or geo. Selects which score leads the report; all four are always computed the same way.
page_type_hintstringnoarticle, faq, howto, pricing, product, docs. Decides which checks apply. Detected automatically when omitted.
baseline_audit_idstringnoAn earlier audit to compare against.
idempotency_keystringnoStrongly recommended. A repeated request returns the original audit instead of spending a second credit.
prompt_sample_set_idstringnoA saved prompt set for citation sampling.
tagsstring[]noUp to 10 labels.

Returns an Audit object. Audits have their own monthly allowance, separate from extraction credits.

Report formats

GET /v1/audits/{id}/report?format=markdown&constructs=1
GET /v1/audits/{id}/report?format=csv&rows=recommendations
GET /v1/audits/{id}/report?format=json

markdown and csv return text rather than JSON. constructs=1 embeds the copy-ready implementation assets in the markdown report.


Schedules

Create and manage recurring extractions that watch a page and report changes.

POST   /v1/schedules
GET    /v1/schedules
GET    /v1/schedules/{id}
PATCH  /v1/schedules/{id}
DELETE /v1/schedules/{id}
POST   /v1/schedules/{id}/run     # run once, immediately

Create body

FieldTypeRequiredDescription
urlstringyesPage to watch.
intentstringnoWhat to extract each run.
cadencestringyesOne of every_6h, twice_daily, daily, weekdays, weekly, monthly, or a cron expression.
alert_emailstringnoAddress to notify when the page changes.
expires_atstringnoISO-8601 date after which the schedule stops.
namestringnoA label for the schedule.

Returns a Schedule object.


Webhooks

To receive change alerts programmatically instead of (or in addition to) email, register a webhook URL in Account → API keys → Webhooks. When a scheduled run detects a change, DatIQ POSTs an event:

{
  "type": "schedule.changed",
  "created_at": "2026-06-20T09:00:00Z",
  "data": {
    "schedule_id": "sch_123",
    "url": "https://example.com/pricing",
    "extraction_id": "ex_456"
  }
}

Respond with 2xx within 5 seconds to acknowledge. DatIQ retries failed deliveries with exponential backoff.


Response schemas

Extraction object

{
  "id": "ex_2eqi99p",
  "url": "https://lumio.io",
  "title": "Lumio — Product analytics that actually make sense",
  "intent": "summary",
  "summary": "Lumio is a product-analytics platform aimed at fast-moving teams…",
  "headings": [
    { "level": 1, "text": "Product analytics that actually make sense" },
    { "level": 2, "text": "Built for teams who move fast" }
  ],
  "links": [
    { "text": "Pricing", "href": "https://lumio.io/pricing", "category": "internal" },
    { "text": "LinkedIn", "href": "https://linkedin.com/company/lumio", "category": "social" }
  ],
  "enrichments": {},
  "created_at": "2026-06-20T13:49:26Z"
}
FieldTypeDescription
idstringUnique extraction id.
urlstringThe page that was extracted.
titlestringThe page's title.
intentstringThe intent used for this extraction.
summarystringPlain-language AI overview (present for summary and most intents).
headingsarrayHeading outline. Each item: level (1–6) and text.
linksarrayLinks found. Each item: text, href, and category (internal / external / social).
enrichmentsobjectMap of any enrichment results attached to this extraction (keyed by focus).
created_atstringISO-8601 creation time.

When intent is map, the response also includes a site_map array of discovered URLs. When intent is pricing or contacts, the relevant structured data appears under enrichments.

Batch object

{
  "id": "batch_zdldy51",
  "status": "completed",
  "intent": "summary",
  "total": 2,
  "succeeded": 2,
  "failed": 0,
  "created_at": "2026-06-20T13:57:45Z",
  "results": [
    { "url": "https://example.com", "status": "succeeded", "extraction": { "id": "ex_tkp20mc" } },
    { "url": "https://stripe.com",  "status": "succeeded", "extraction": { "id": "ex_6tt10md" } }
  ]
}

status is one of queued, running, completed. Each result's status is succeeded or failed (failed entries include an error message).

Audit object

{
  "audit_id": "aud_01K123ABCXYZ",
  "target": {
    "url": "https://example.com/guide/what-is-geo",
    "page_type": "article",
    "device_profile": "mobile",
    "audit_profile": "balanced"
  },
  "framework_scores": { "overall": 78.4, "seo": 75.2, "aeo": 82.1, "geo": 77.3 },
  "coverage": 92.5,
  "pillar_scores": {
    "answer_clarity": {
      "score": 84.0,
      "weight": 0.30,
      "coverage": 100,
      "signals": {
        "direct_answer_block": 100,
        "conciseness": 88,
        "passage_independence": 79,
        "question_headings": 70,
        "extractable_formatting": 82
      }
    },
    "technical_accessibility": {
      "score": 76.0,
      "weight": 0.25,
      "coverage": 70,
      "signals": {
        "crawl_index_eligibility": 90,
        "render_completeness": 70,
        "core_web_vitals": null,
        "mobile_parity": 100,
        "structured_data_validity": 78
      }
    }
  },
  "penalties": [
    {
      "code": "AI_CRAWLER_PARTIAL_BLOCK",
      "severity": "medium",
      "penalty_factor": 0.05,
      "description": "One or more AI crawlers appear blocked in robots directives."
    }
  ],
  "score_math": { "pre_penalty_total": 82.5, "penalty_multiplier": 0.95, "final_score": 78.4 },
  "issues": [
    {
      "code": "SH-06",
      "pillar": "structural_hierarchy",
      "severity": "high",
      "frameworks": ["aeo", "seo"],
      "title": "Visible FAQs carry no FAQPage schema",
      "evidence": "6 visible question-and-answer pairs carry no FAQPage markup."
    }
  ],
  "recommendations": [
    {
      "id": "rec_901",
      "code": "SH-06",
      "priority": "high",
      "priority_score": 58.4,
      "owner": "seo",
      "frameworks": ["aeo", "seo"],
      "title": "Add FAQPage JSON-LD whose wording matches the visible questions and answers exactly.",
      "rationale": "The content is already there; the markup is what makes it eligible for direct extraction.",
      "estimated_lift": 4.8,
      "implementation_asset": {
        "type": "jsonld",
        "format": "html",
        "label": "FAQPage schema",
        "body": "<script type=\"application/ld+json\">{ ... }</script>"
      },
      "status": "open"
    }
  ],
  "stage_errors": []
}

null is not 0. A signal that reads null was not measured — the external service was unavailable, or the check does not apply to this page type. It is EXCLUDED from its pillar and its weight is redistributed across the signals that were measured, rather than being scored as a failure.

That is what coverage reports: the share of intended evidence this audit actually gathered. A score of 92 built on 70% coverage is not the same as a 92 built on all of it, and your code should treat them differently. stage_errors lists what could not be gathered and why.

penalties are multiplicative and apply to every framework score, not only the overall one. score_math shows the arithmetic.


Schedule object

{
  "id": "sch_ts2whjj",
  "name": "Track · lumio.io/pricing",
  "url": "https://lumio.io/pricing",
  "intent": "summary",
  "cadence": "daily",
  "status": "active",
  "alert_email": "you@company.com",
  "last_run_at": "2026-06-20T13:59:15Z",
  "last_status": "unchanged",
  "next_run_at": "2026-06-21T09:00:00Z",
  "created_at": "2026-06-20T13:58:56Z"
}

status is active or paused. last_status is unchanged or changed.

Enrichment object

{
  "focus": "contacts",
  "data": {
    "emails": ["press@lumio.io"],
    "people": [{ "name": "Jane Doe", "role": "VP Marketing" }]
  }
}

The shape of data depends on focus.


Errors

Errors use standard HTTP status codes and a consistent JSON envelope:

{
  "error": {
    "code": "invalid_request",
    "message": "The 'url' field is required."
  }
}
StatuscodeMeaning
400invalid_requestMissing or malformed parameters.
401unauthorizedMissing or invalid API key.
402quota_exceededMonthly extraction allowance reached.
403forbiddenYour plan doesn't include this capability.
404not_foundNo such resource.
422unprocessableThe target page could not be extracted (blocked, non-HTML, unreachable).
429rate_limitedToo many requests; retry after the reset.
5xxserver_errorTransient problem on DatIQ's side; retry with backoff.

Example: end-to-end (Node.js)

const API = "https://api.datiq.app/v1";
const key = process.env.DATIQ_API_KEY;
const headers = { Authorization: `Bearer ${key}`, "Content-Type": "application/json" };

// 1. Extract a page
const res = await fetch(`${API}/extractions`, {
  method: "POST",
  headers,
  body: JSON.stringify({ url: "https://example.com", intent: "summary" }),
});
const extraction = await res.json();

// 2. Enrich it with contacts
await fetch(`${API}/extractions/${extraction.id}/enrichments`, {
  method: "POST",
  headers,
  body: JSON.stringify({ focus: "contacts" }),
});

// 3. Generate a competitor summary
const content = await fetch(`${API}/extractions/${extraction.id}/content`, {
  method: "POST",
  headers,
  body: JSON.stringify({ format: "competitor_summary" }),
}).then((r) => r.json());

console.log(content.content);

Support

Questions about the API? Email hello@datiq.app. For account, billing, and plan upgrades to unlock API access, see the Account screen in the app.


v1.0 preview endpoints

The following endpoints are scheduled for the v1.0 release. They are documented here ahead of general availability so integrators can plan around them; treat them as a preview and pin to the versioned base URL.

Create a public shareable report

POST /v1/extractions/{id}/share

Turn an existing extraction into a public, read-only report at https://datiq.app/p/{slug}. Anyone with the link can view it; no DatIQ account required.

Request body

FieldTypeRequiredDescription
ttl_daysintegernoAuto-expire the public report after N days. Omit for "no expiry".

Response

{
  "slug": "a8K2mQ4x",
  "url": "https://datiq.app/p/a8K2mQ4x",
  "expires_at": "2026-08-15T00:00:00Z"
}

Revoke a public report

DELETE /v1/extractions/{id}/share

Removes the public report; the underlying extraction is unaffected.

GET /v1/gallery?limit=20&cursor=...

Returns recent public extractions across all users. Useful for discovery integrations.

Response

{
  "data": [
    {
      "slug": "a8K2mQ4x",
      "title": "Acme pricing",
      "intent": "pricing",
      "url": "https://datiq.app/p/a8K2mQ4x",
      "created_at": "2026-07-15T10:00:00Z"
    }
  ],
  "next_cursor": null
}

Submit feedback on an AI summary

POST /v1/extractions/{id}/feedback

Record a thumbs-up / thumbs-down rating on the AI summary, optionally with a free-text comment.

Request body

FieldTypeRequiredDescription
ratingstringyesup or down.
commentstringnoFree-text feedback.

This data is used to improve the AI model.


Planned endpoints

These surfaces exist in the app today and are on the roadmap for the public API. They are listed so you can plan around them; they are not callable yet, and this section will be replaced by full reference entries when they ship.

AreaPlanned resourcesWhat it will let you do
Workflow templates/v1/templates, /v1/templates/{key}/runsList the catalogue, start a run with an input payload, poll or receive its result.
Account lists/v1/lists, /v1/lists/{id}/items, /v1/lists/{id}/runsImport domains, start enrichment, read back scored accounts with coverage and provenance.
ICP rules/v1/icp-rulesRead and update the weighted criteria and threshold an account list is scored against.
Watchlists/v1/watchlists, /v1/watchlists/{id}/changesCreate a watch, set its cadence, and read the classified change feed.
Signal rules/v1/signal-rulesManage routing rules programmatically instead of in the app.
Reports/v1/reports, /v1/reports/{id}/visibilityPublish a result as a report and change or revoke its visibility.

Until they land, the supported integration pattern for these surfaces is: configure the workflow in the app, and route its output to your systems with a webhook signal rule.