We are currently building something exciting and will be launching soon. Registration is temporarily closed. Launching soon — registration temporarily closed.

Developer Docs API version: v1

API Reference

Complete endpoint documentation for the Sentiqra Analyze API.

Base URL

https://sentiqra.tech/v1

Authentication

Bearer token in the Authorization header.

Request headers

Header Required Description
AuthorizationProtected endpointsBearer API key. Keys start with sq_live_.
Idempotency-KeyOptionalSafe-retry key on POST endpoints - replays return the recorded response without re-billing.
X-Retry-FailedOptionaltrue + an existing Idempotency-Key retries only the analyzers recorded as failed - billed per newly-completed run.
Content-TypePOST requestsapplication/json

Response headers

Header Description
X-Sentiqra-Request-IDUnique request identifier - include it in support requests and audit logs.
X-Sentiqra-Detection-ConfigAnalyzer configuration version that produced the response (sqcfg_...).
verification.fingerprint(response body field, not a header) Deterministic analysis fingerprint (fp2_... - RFC 8785 canonical payload) - store it with the signature to verify the response later.
X-Sentiqra-Analyzers-RunAnalyzer runs billed to this request (1 or 2 per analyze call).
MCP-Protocol-VersionMCP protocol version on /mcp responses. Analyzer runs billed by an MCP call are reported in the result's structuredContent (billed_runs), not a header.
X-Sentiqra-API-ContractAPI contract version that served the response.
X-RateLimit-LimitMaximum requests per second for your plan
X-RateLimit-RemainingRemaining requests in the current window
X-RateLimit-ResetUnix timestamp when the rate limit resets
POST /v1/analyze

Run one or two analyzers and return a flat list of structured signals.

Auth: Bearer token

Parameters

Name Type Required Description
text string Yes The text to analyze (max 4,096 Unicode code points, counted after stripping surrounding whitespace; no Unicode normalization). Longer input is rejected with input_too_long - it is never truncated; split long documents into chunks yourself.
language string No Language code supported by the requested analyzer(s) — ISO 639-1, or 639-3 where no 639-1 code exists (e.g. arz, pcm). Defaults to en.
analyzers array Yes One or two explicit analyzer slugs (e.g. ["trust-safety", "cybersecurity"]). Required - there is no run-everything option.
detection_config string No Configuration pin - an sqcfg_* identifier from verification.configuration, valid only for the analyzer set that issued it. Omitted = current configuration. See Configuration pinning below for lifecycle states and errors.

Example Request

{
  "text": "you are a worthless idiot",
  "language": "en",
  "analyzers": ["trust-safety"]
}

Example Response

{
    "language": "en",
    "language_source": "declared",
    "signals": [
        {
            "analyzer": "trust-safety",
            "code": "insults_derogation",
            "label": "Insults & Derogation",
            "score": 0.86,
            "level": "category"
        },
        {
            "analyzer": "trust-safety",
            "code": "insult",
            "label": "Insult",
            "score": 0.99,
            "level": "label",
            "parent": "insults_derogation"
        },
        {
            "analyzer": "trust-safety",
            "code": "belittling",
            "label": "Belittling",
            "score": 0.99,
            "level": "label",
            "parent": "insults_derogation"
        }
    ],
    "meta": {
        "analyzers": [
            {
                "name": "trust-safety",
                "status": "completed",
                "applicability": "analyzable",
                "assessment": "signals_detected",
                "signal_count": 3,
                "billed": true
            }
        ]
    },
    "usage": {
        "analyzer_runs": 1,
        "billed": true
    },
    "verification": {
        "version": 3,
        "configuration": "sqcfg_ZZW77NM9",
        "fingerprint": "fp2_8a72c4...19f",
        "input_commitment": "ic3_31bd5e...a42",
        "signature": "sig_ed25519_4c1f...e2a",
        "key_id": "edk_af4f218e",
        "binding_key_id": "bk_31bd5e42f7a019c8"
    }
}
POST /mcp

JSON-RPC 2.0 endpoint for AI-agent tool calls (MCP protocol 2025-06-18) - a separate orchestration surface from /v1/analyze with the same Bearer API key, the same plan analyzer/language entitlements, and the same account usage ledger. tools/list is the authoritative inventory: every tool declares its analyzer set and maximum billable runs under _meta (contract sentiqra/mcp-tool/v1). The billing unit is the analyzer run, not the tool invocation - each single-analyzer detect_* tool bills at most one run per call, while detect_all executes a fixed set of the eight MCP-exposed analyzers and can consume up to eight runs (the REST-only analyzers insurance, dating-safety, fraud-scam, and wellness are not exposed over MCP). A tool's declared maximum is reserved from account quota before execution and only completed analyzer runs are billed, so a call can never exceed its budget - and any analyzer outside your plan or key scope fails the whole call rather than being skipped. initialize, tools/list, ping, and notifications are authenticated but never billed.

Auth: Bearer token (Sentiqra API key - re-validated server-side; OAuth or third-party tokens are not accepted)

Parameters

Name Type Required Description
method string Yes JSON-RPC method: initialize, tools/list, tools/call, or ping.
params object No tools/call takes {"name": "<tool>", "arguments": {"text": "...", "language": "en"}}. Tool inputs are text + language only - there is no detection_config parameter; every call runs the current deployed configuration, reported in the result.

Example Request

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "detect_trust_safety",
    "arguments": {"text": "you are a worthless idiot", "language": "en"}
  }
}

Example Response

{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "content": [{"type": "text", "text": "Analysis results for Trust & Safety (language: en):\n\nSignals (1):\n  1. Insults & derogation - score: 90.0%\n\nRaw JSON:\n{...}"}],
    "structuredContent": {
      "analyzers": [{"analyzer": "trust-safety", "status": "completed", "billed": true}],
      "analyzer_runs": 1,
      "billed_runs": 1,
      "max_billable_runs": 1
    }
  }
}

// detect_all returns the same envelope with one analyzers[] entry per
// MCP-exposed analyzer and max_billable_runs: 8. statuses: completed,
// failed, timeout, overloaded, denied - only billed:true runs settle.
GET /v1/meta/domains

List production analyzer identifiers, names, and availability - everything needed to construct a valid request. Send a Bearer API key to additionally receive supported languages, taxonomy counts, family, and the catalog version.

Auth: Optional - Bearer token unlocks detailed metadata

Example Response

{
  "domains": [
    {
      "id": "trust-safety",
      "name": "Trust & Safety",
      "status": "production",
      "v2_endpoint": "/v1/analyze/trust-safety",
      "aliases": []
    }
  ]
}

// With Bearer token, responses also include:
//   "catalog_version": "dcat_R7K2N4"
//   per domain: family, taxonomy counts, supported languages
GET /v1/meta/domains/{domain}

Get canonical metadata for one production analyzer. Anonymous responses contain identifier and availability only; send a Bearer API key for languages and taxonomy counts. Planned catalog products are not exposed as active domains.

Auth: Optional - Bearer token unlocks detailed metadata

Parameters

Name Type Required Description
domain string Yes Canonical domain identifier such as trust-safety or customer-service

Example Request

GET /v1/meta/domains/customer-service
POST /v1/verify

Verify a detection receipt signature. Submit the verification object from a detection response; returns whether the signature is authentic. Accepts current Ed25519 receipts (fingerprint + input_commitment + signature) and legacy HMAC receipts (fingerprint + signature).

Auth: None

Parameters

Name Type Required Description
fingerprint string Yes Result fingerprint (fp_…) from the receipt
input_commitment string No Caller-keyed input commitment (ic_…). Required on current receipts.
signature string Yes sig_ed25519_… for current receipts, sig_… for legacy receipts

Example Request

{
  "fingerprint": "fp_8a72...19f",
  "input_commitment": "ic_31bd...a42",
  "signature": "sig_ed25519_4c1f...e2a"
}

Example Response

{
  "valid": true,
  "configuration": "sqcfg_ZZW77NM9",
  "fingerprint": "fp_8a72...19f"
}
GET /v1/verify/public-key

Publish the Ed25519 public key that signs detection receipts, enabling fully offline receipt verification. key_id in each receipt selects the key after rotation.

Auth: None

Example Request

GET /v1/verify/public-key

Example Response

{
  "algorithm": "ed25519",
  "key_id": "edk_af4f218e",
  "public_key": "b697a3c4aca5cbba3ac724f2abba75ca29781e490f7e6d8367320632de0f899b",
  "signed_payload": "fingerprint + '|' + input_commitment"
}
GET /v1/account/usage

Current billing-period usage for the authenticated account: analyzer runs consumed, quota, and overage state.

Auth: Bearer token

Example Request

GET /v1/account/usage

Example Response

{
  "plan": {"tier": "growth", "family": "analysis"},
  "period": {"starts_at": "2026-11-01T00:00:00Z", "ends_at": "2026-12-01T00:00:00Z"},
  "usage": {"used": 12034, "limit": 150000, "remaining": 137966, "overage_units": 0}
}
GET /v1/status

Report each analyzer's operational state and the opaque configuration alias (sqcfg_*) it currently runs - the same value receipts carry in verification.configuration and the value to copy into a detection_config pin.

Auth: None

Example Request

GET /v1/status

Example Response

{
  "domains": {
    "trust-safety": {
      "state": "operational",
      "configuration": "sqcfg_ZZW77NM9",
      "indexes_loaded": 1,
      "indexes_available": 21
    }
  }
}

// One entry per analyzer. Aliases rotate with each configuration change -
// an older alias stays valid for receipt verification but is not a valid pin.
GET /v1/meta/webhook-events

List the webhook event types your account can subscribe to.

Auth: None

Example Request

GET /v1/meta/webhook-events
GET /v1/openapi.json

Machine-readable OpenAPI contract for the public API - the source of truth SDKs and Postman collections are generated from.

Auth: None

Example Request

GET /v1/openapi.json

Error Codes

Status Code Description
200OKDetection completed successfully
400invalid_request · bad_requestMissing or invalid parameters, or malformed JSON. Related codes: unknown_parameter, unsupported_language, input_too_long (text over 4,096 Unicode code points), invalid_detection_config (malformed configuration pin). Request-contract codes: duplicate_field (repeated JSON property name), unknown_field, request_too_deep (nesting over 64), invalid_unicode (unpaired \uXXXX surrogate), invalid_utf8, ambiguous_request (query parameters on a body-only endpoint, or a body on a query-only endpoint)
401missing_api_key · invalid_api_keyMissing or invalid API key
403domain_not_in_plan · language_not_in_planAPI key does not have access to the requested analyzer or language. Reserved for restricted products, scoped API keys, and custom arrangements - all GA analyzers and their supported languages are included on every plan. Also: account_suspended, account_terminated, ip_not_allowed, version_pinning_not_available (detection_config without the pinning entitlement)
409idempotency_conflict · idempotency_in_progressSame Idempotency-Key replayed with a different body, or the original request is still running
410configuration_retiredPinned detection configuration reached the unavailable lifecycle state - the current configuration is never substituted. See Configuration pinning
413 · 415payload_too_large · unsupported_media_typeBody over the 1 MiB contract limit, or a non-JSON Content-Type on a JSON endpoint — the request is rejected before any processing.
422configuration_scope_mismatch · configuration_unavailable · insufficient_contentPinned configuration belongs to a different analyzer set, or is unknown/unresolvable - the request fails before any run executes and the current configuration is never substituted. insufficient_content: the text contains no analyzable letters (emoji-only, numeric-only, punctuation-only) - nothing executed, nothing billed. On /v1/analyze this appears per-analyzer as not_applicable instead.
429rate_limit_exceededRate limit exceeded - check X-RateLimit-Reset. Also: monthly_quota_exceeded, overage_cap_reached, spend_cap_reached, key_spend_cap_reached
500internal_errorServer error. Retry with exponential backoff.
503usage_unavailable · service_unavailableUsage metering or detection engine temporarily unavailable

Request Contract — One Interpretation

Every JSON endpoint enforces a single canonical interpretation of the request before authentication, validation, analysis, idempotency, or billing see it. A request the proxy, the parser, and the analyzer could read differently is rejected outright — it can never authorize under one reading and execute or bill under another. Rules applied to every request body:

  • •Content type. JSON endpoints accept application/json only, UTF-8 encoded. Form submissions, text/plain, or a non-UTF-8 charset declaration return 415 unsupported_media_type.
  • •Body shape. Exactly one JSON object per request — maximum 1 MiB and 64 levels of nesting, nothing before or after it. A repeated property name is a 400 duplicate_field error at any depth: parsers disagree about which occurrence wins, so the request is ambiguous by definition.
  • •Unicode. The body must be valid UTF-8, and \uXXXX escapes must encode real code points — a lone surrogate half is invalid_unicode, never silently replaced.
  • •Unknown fields. Fields outside the endpoint's schema are 400 unknown_parameter errors — including unsupported configuration selectors and any field attempting to set tenant, account, actor, or key identity. Identity comes only from the Bearer credential; a body field can never change who is authorized or billed.
  • •Query vs. body. Endpoints whose contract is body-only reject query parameters, and GET detection endpoints (query-only) reject request bodies — both as ambiguous_request. Parameters never silently compete or get dropped.

A rejected request executes nothing, reserves nothing, and bills nothing — the check runs before entitlement and usage accounting. The same parsed request then drives authorization, configuration selection, analysis, the idempotency request hash, and usage settlement end to end.

Text Limits

text accepts at most 4,096 Unicode code points counted on the submitted UTF-8 string after stripping leading and trailing whitespace. A code point is one Unicode character - a combining accent counts separately (e.g. e + ◌́ = 2), and an emoji outside the Basic Multilingual Plane counts as 1 (not the 2 UTF-16 units a JavaScript .length reports). Input is validated as submitted - no Unicode normalization is applied and input is never truncated. Oversized input is rejected with 400 input_too_long.

Longer material is chunked in your environment, before submission: each chunk is analyzed as an independent snippet, and every successfully analyzed chunk consumes analyzer runs from your quota - a 3-chunk document analyzed by 2 analyzers consumes 6 runs. Chunk-level signals describe the submitted snippet only; a signature or receipt verifies what was sent in that request, not your source document, and any document-level conclusion is a customer-side aggregation. How you extract, normalize, split, and combine is outside Sentiqra's reproducibility guarantee unless you record it - the input-preparation contract (sentiqra/prepare/v1) does that: deterministic sentence-atomic chunking that preserves speaker turns and quoted material, explicit NFC normalization, marked overlap, per-chunk language assignment, and a customer-held manifest binding each request and returned receipt back to source offsets.

Language & Input Handling

language is a declaration, not a detection result. Sentiqra analyzes text under the language you declare; omitting it applies the documented English default and reports language_source: "default" (vs. "declared") at the top level. The API does not detect or split languages:

  • •Mixed-language text is analyzed under the single declared language. Signal quality on the non-declared portions is unspecified - split mixed-language input upstream when it matters.
  • •Incorrect declarations produce a valid result computed against the wrong language's coverage - the API cannot detect a wrong declaration. Declare accurately.
  • •Language fallback. When the declared language is supported by the analyzer but is not a dedicated coverage language, analysis runs under English coverage and reports applicability: "language_fallback" plus effective_language. When the analyzer has no coverage at all, it reports status: "not_applicable" + applicability: "unsupported_language" (unbilled; 400 when no requested analyzer covers the code).
  • •No analyzable content (emoji-only, numeric-only, punctuation-only, symbol-only): single-analyzer endpoints return 422 insufficient_content; /v1/analyze marks each requested analyzer not_applicable. Nothing executes and nothing is billed.
  • •Fragments and short inputs execute normally - weak evidence resolves to no_signals or abstained, never a forced guess.
  • •Encoded content (base64, hex, quoted-printable) is analyzed literally as submitted. Decode upstream when the encoded payload is what you want analyzed.

Coverage is per-analyzer - the supported-language set differs across analyzers. Check the analyzer's language matrix before declaring a code. See the conditions table for how to route each outcome.

Score Semantics & Output Profiles

A score expresses signal-match strength under a particular analyzer configuration. It is not a probability that the signal or a downstream action is correct. Validate action thresholds on representative labeled data.

Scores are not comparable across labels or analyzers unless validated on your own labeled traffic. Two versioned output profiles intentionally expose different score precision - a profile's field set and semantics never change in place; a different shape ships as a new profile name and version. The response example above shows profile full.v1; see Understanding signals for the field-level reference.

Output profileApplies toscoreconfidence
full.v1 All non-free entitlement tiers Continuous value in [0, 1] Absent
reduced.v1 Anonymous traffic (playgrounds, demos) and free-tier API keys Band's representative value (at most 5 signals) Present - band name

Under reduced.v1, confidence names the band and score carries that band's representative value:

confidenceReturned scoreBand boundary (public)
very_high 0.9 ≥ 0.85
high 0.7 0.65 – < 0.85
medium 0.5 0.45 – < 0.65
low 0.3 0.00 – < 0.45

Interfaces

Sentiqra exposes the same analyzers through three interfaces with deliberately different capabilities. REST is the request/response interface; MCP is the agent interface; the playground is an anonymous demo. The matrix below is the published contract - it is generated from the same registry as the rest of this page.

REST API MCP server Anonymous playground / demo
Endpoints POST /v1/analyze, POST /v1/analyze/{analyzer} POST /mcp (JSON-RPC tools/call) portal demo surface (curated samples via server-side demo key)
Analyzers all GA analyzers 8 MCP-exposed analyzers via detect_* tools; detect_all runs exactly those eight the 6 demo analyzers (trust-safety, cybersecurity, crisis-intelligence, disinformation, emotions, customer-service)
Max analyzers / call 2 8 1
Configuration pinning detection_config field (paid-tier entitlement) not available - always the current deployed configuration not available
Output profile full.v1 for non-free tiers, reduced.v1 for free per-key entitlement, same as REST (free keys get reduced shaping) reduced.v1 (banded scores, max 5 signals)
Receipt signed v3 receipt on every 200 response (incl. all-not_applicable) classification fingerprint + configuration reported per result; no signed REST-style receipt server-reminted v3 receipt over the reduced response
Authentication Bearer sq_live_* API key Bearer sq_live_* API key none (server-side demo credential; anonymous quota)
Retries Idempotency-Key replay (24h) + X-Retry-Failed child retries no idempotency layer - retry a call as a new request; billing is per executed analyzer run not applicable - re-run the demo

Configuration Pinning (detection_config)

Send detection_config to pin the configuration a request runs against. The value is an opaque sqcfg_* identifier copied from verification.configuration in a previous response, or from GET /v1/status for the current configuration of each analyzer.

A configuration ID is scoped to an analyzer set: a single analyzer slug, or the canonical sorted set a multi-analyzer request produced (the composite scope in its receipt). A pin is valid only for the exact analyzer set in the request - submitting a single-analyzer ID for a two-analyzer request, or a different analyzer's ID, is a scope mismatch. Output profile (full/reduced) and language do not change the configuration.

When detection_config is omitted the request runs the current configuration for the requested analyzer set. Omission never selects a historical configuration and never carries a previous request's pin forward.

Configuration lifecycle

State Requests Meaning
current accepted The configuration each analyzer runs today. Its alias appears in every receipt and per domain in GET /v1/status. Requests that pin it execute normally.
supported historical accepted A previously current configuration still within its published support window. Requests that pin it reproduce the original canonical result for identical input. No longer the default - requests without a pin run the current configuration.
deprecated accepted A supported historical configuration with an announced retirement date. Requests still execute and reproduce results; callers should migrate pins before the state becomes unavailable.
unavailable rejected A configuration outside its support window. Requests that pin it fail with a documented error; the current configuration is never substituted.

The current configuration is immutable while it is current. Configurations that rotate out remain supported historical for the window published in the changelog entry that introduced their successor; on Enterprise agreements the support window is a contractual commitment for the life of the contract - subject to the security-suspension rule below, which can pause execution (never verification) of any configuration while it applies.

Replay an analysis using its original input and supported configuration ID. Configuration availability follows the published support policy or your contract.

Security suspension

A configuration pins LOGICAL behavior, not a permanently running build. When a dependency, runtime, or deployment component serving a configuration becomes unsafe, a confirmed security_vulnerability incident may suspend execution of the affected scope: pinned and unpinned requests that would execute it fail with configuration_suspended; nothing is substituted and no different detector answers in its place. Execution resumes only after the patched build passes the compatibility attestation path (reproducibility report proving the configuration's promised behavior is unchanged), or the configuration is retired through the documented lifecycle with notice. Where neither is immediately possible, a narrowly-scoped replay arrangement - an isolated deployment approved per engagement - may serve historical replay while the suspended build stays out of the general path. Receipt verification is independent of execution: a suspended or retired configuration's receipts still verify against the published key set - /v1/verify performs cryptographic verification, never re-execution, so availability of one never depends on the other.

Pinning errors

A rejected pin fails the request before any analyzer run executes and is never billed. The current configuration is never silently substituted.

Status Code When
400invalid_detection_configThe value is not an sqcfg_* identifier.
403version_pinning_not_availableThe plan does not include the version-pinning entitlement.
410configuration_retiredThe pinned configuration reached the unavailable lifecycle state.
422configuration_scope_mismatchThe pin was issued for a different analyzer set than the request's.
422configuration_unavailableThe ID is unknown or can no longer be resolved.
503configuration_suspendedExecution of the configuration is suspended by a confirmed quality or security incident. Verification of its receipts is unaffected. Pin a supported historical configuration outside the incident scope, or retry after restoration.

Replaying an analysis

  1. Run an analysis. The receipt names the configuration that produced it in verification.configuration.
  2. Replay the same input with that ID in detection_config.
  3. Compare the canonical result: identical language, identical signals (order, codes, scores), and identical verification.configuration.
curl -s https://sentiqra.tech/v1/analyze \
  -H "Authorization: Bearer $SENTIQRA_API_KEY" -H "Content-Type: application/json" \
  -d '{"text": "you are a worthless idiot", "language": "en", "analyzers": ["trust-safety"]}'

# → "verification": { "configuration": "sqcfg_ZZW77NM9", "fingerprint": "fp2_…", … }

curl -s https://sentiqra.tech/v1/analyze \
  -H "Authorization: Bearer $SENTIQRA_API_KEY" -H "Content-Type: application/json" \
  -d '{"text": "you are a worthless idiot", "language": "en", "analyzers": ["trust-safety"], "detection_config": "sqcfg_ZZW77NM9"}'

# → same signals and the same verification.configuration.

Replay is guaranteed while the configuration remains current or supported historical under the published support policy or your contract — not indefinitely, and subject to the security-suspension rule: an unsafe execution environment pauses execution (never receipt verification) until a patched build passes compatibility attestation.

Rate Limits

Rate limits vary by plan. Exceeding the limit returns 429 rate_limit_exceeded - check X-RateLimit-Reset for the retry time.

Monthly quota works differently per plan. Free is a hard cap: quota exhaustion returns 429 monthly_quota_exceeded until the next billing cycle or an upgrade. Paid plans continue past quota into automatic overage billing at the plan's per-1K rate; you get 429 overage_cap_reached or 429 spend_cap_reached only at the plan's overage ceiling or your configured cap.

Plan RPS Monthly Analyzer Runs Price
Free 2 5,000 Free
Build 10 50,000 $149/mo
Growth 25 150,000 $349/mo
Production 50 500,000 $799/mo
Scale 200 2,500,000 $2,999/mo
Enterprise By agreement By agreement By agreement

Plan prices and quotas are also shown on the pricing page - both read the same source.

Idempotency & partial results

Send an Idempotency-Key header on POST /v1/analyze to make retries safe. Re-submitting the same key with the same canonical request replays the recorded response — marked by X-Sentiqra-Idempotent-Replay: true — with no additional charge. The request identity covers the request fields (including detection_config); the same key with a different body returns 409 idempotency_conflict. Idempotency records hold the key, a hash of the request fields, per-analyzer outcomes, and the response for 24 hours — your submitted text is never persisted. A fresh key is a new logical operation and bills normally.

When one of two requested analyzers fails, the response still returns the completed analyzer's signals. Check each entry in meta.analyzers[] — status is completed, failed, overloaded, or not_applicable, and billed shows whether the run counted against your quota. A failed analyzer is never reported as a successful empty result — meta.partial marks the response incomplete.

Three separate fields describe what happened per analyzer: status (did it execute), applicability (analyzable, language_fallback, insufficient_content, or unsupported_language), and assessment for completed runs (signals_detected, no_signals, abstained). An empty signals array alone is never a verdict — no_signals means nothing crossed threshold (not proof of safety), abstained means a validated rule declined to report, and not_applicable means nothing ran at all. See the Production Guide conditions table for routing.

A plain replay returns the recorded outcome verbatim — it never silently retries failed analyzers. To retry them, resubmit the same key and body with X-Retry-Failed: true: this explicit child operation re-executes only the failed analyzers, merges their results into the recorded response, and bills only newly-completed runs (usage.billed_runs shows this request's charge). A second child with nothing left to retry returns 409 no_failed_analyzers. See the Production Guide for the full failure-mode matrix.

Versioning & Changelog

The current API version is v1. We use URL-based versioning (/v1/analyze). Breaking changes require a new version number and are announced at least 90 days before the old version is retired; non-breaking changes (new endpoints, new optional parameters, new response fields) are added to the current version.

v1.0.0Initial release: POST /v1/analyze, per-analyzer /v1/analyze/{domain} endpoints, GET /v1/meta/domains, GET /v1/account/usage, account webhooks.

Ready to integrate?