whoisgeni-us Analysis API

The analysis API from whoisgeni-us — 3 operation(s) for analysis.

Operations 3

POST /analyze Submit domain for analysis #
POST /analyze/batch Submit batch domain analysis #
POST /analyze/bulk Submit bulk domain analysis (results emailed) #

Work with this as data

Every API here is available over the APIs.io API and to AI agents over MCP.

MCP server

One button, every client — Claude, Cursor, VS Code and the rest.

https://apis.io/mcp

Tools for apis

7 MCP tools reach this
  • find_apisBrowse and filter every API in the catalog.
  • get_api_artifactsOne API's artifacts, grouped by type.
  • get_openapiThe primary OpenAPI for this API.
  • find_similar_apisAPIs that look like this one.
  • apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.
  • resolveTurn a domain, URL or GitHub org into the provider it belongs to.
  • find_cohortsEvery scored population of providers in the catalog.
All 92 tools →

Call it yourself

curl for this page
This API
curl "https://apis.io/api/v1/apis/whoisgeni-us:whoisgeni-us-analysis-api"
All apis
curl "https://apis.io/api/v1/apis?limit=25"

Discovery needs no key. Ratings and market analysis are Pro.

Get an API key

Free tier, no form to fill in. Signing in shares your email address with us — we store it to create your key and to recognise you if you sign in with another provider. See our Privacy Policy and Terms.

A second provider on the same verified email joins the account you already have.

OpenAPI Specification

whoisgeni-us-analysis-api-openapi.yml Raw ↑
openapi: 3.2.0
info:
  title: WhoisGenius Analysis API
  description: 'Domain intelligence platform with AI-powered operator attribution Responses are JSON by default; request the compact, token-efficient TOON format with the `Accept: application/toon` header.'
  version: 0.1.0
tags:
- name: Analysis
paths:
  /analyze:
    post:
      tags:
      - Analysis
      summary: Submit domain for analysis
      description: 'Submit a single domain for analysis.


        Creates an analysis job and returns 202 with a job_id for polling.

        Deduplicates against active jobs unless force_refresh is True.

        An audit log entry is written in the background.


        Set ``wait=true`` for a one-call flow: the request is held briefly and

        returns the result inline (HTTP 200) when the analysis resolves, or HTTP 202

        with the job_id to poll if it is still running when the wait budget elapses.


        Set ``depth="quick"`` for the honest fast path: the fast collector subset

        (dns/whois/http_probe/asn/rdns) runs inline under a hard deadline and the

        terminal result comes back as HTTP 200 (same body shape as GET /jobs/{id},

        plus job_id). Quick never runs vision/LLM/reverse-WHOIS/metered third-party

        enrichment -- it is the fast honest answer; deep is the full one. Quick

        cannot be combined with wait=true or force_refresh (400), costs the same

        1 credit as deep, and refunds on a failed outcome.


        Quota enforcement: each query increments a monthly Redis counter.

        Free tier users are hard-blocked at their monthly quota

        (``settings.quota_free``). Pro/Team users exceeding quota are billed

        overage via Stripe metered billing. Falls back to credit deduction if

        overage billing unavailable.'
      operationId: submit_analysis_analyze_post
      parameters:
      - name: wait
        in: query
        required: false
        schema:
          type: boolean
          description: When true, hold the response for up to ~20 seconds and return the result inline once ready (same body as GET /jobs/{job_id}) with HTTP 200. If the analysis is still running when the wait budget is spent, return HTTP 202 with the job_id so you can poll GET /jobs/{job_id}. Default false returns 202 immediately.
          default: false
          title: Wait
        description: When true, hold the response for up to ~20 seconds and return the result inline once ready (same body as GET /jobs/{job_id}) with HTTP 200. If the analysis is still running when the wait budget is spent, return HTTP 202 with the job_id so you can poll GET /jobs/{job_id}. Default false returns 202 immediately.
      - name: X-API-Key
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Api-Key
      - name: X-LLM-API-Key
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Llm-Api-Key
      - name: X-LLM-Provider
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Llm-Provider
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SubmitRequest'
      responses:
        '202':
          description: Analysis job accepted
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiResponse_SubmitResponse_'
        '200':
          description: 'wait=true or depth=quick: analysis resolved inline within the request (depth=quick always answers 200 with the terminal result; wait=true answers 200 only when the job resolved inside the wait budget)'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiResponse_JobStatusResponse_'
        '400':
          description: Invalid depth combination (quick + wait/force_refresh)
        '422':
          description: Invalid domain format
        '401':
          description: Unauthorized — missing or invalid API key/JWT.
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: 'null'
                  error:
                    type: object
                    properties:
                      code:
                        type: string
                        example: UNAUTHORIZED
                      message:
                        type: string
                  meta:
                    type: 'null'
  /analyze/batch:
    post:
      tags:
      - Analysis
      summary: Submit batch domain analysis
      description: 'Submit multiple domains for analysis in a single request.


        Processes each domain independently -- partial failures do not abort

        the batch. Returns 202 if all succeed, 207 if some fail, 422 if all fail.

        Each accepted domain gets an audit log entry in the background.


        Quota enforcement: each domain in the batch gets its own atomic Redis

        INCR via check_and_increment. Free tier users are hard-blocked at quota.

        Paid tier overage is allowed and billed via periodic InvoiceItem.


        With ``depth=quick`` every domain runs through the inline fast path

        instead (see POST /analyze): 200 when all resolve, 207 partial, 422 when

        all fail. Quick batches are capped at QUICK_BATCH_MAX_DOMAINS.'
      operationId: submit_batch_analysis_analyze_batch_post
      parameters:
      - name: X-API-Key
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Api-Key
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/BatchSubmitRequest'
      responses:
        '202':
          description: Batch submission results
          content:
            application/json:
              schema: {}
        '200':
          description: 'depth=quick only: every domain resolved inline'
        '207':
          description: Partial success -- some domains failed
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          description: Unauthorized — missing or invalid API key/JWT.
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: 'null'
                  error:
                    type: object
                    properties:
                      code:
                        type: string
                        example: UNAUTHORIZED
                      message:
                        type: string
                  meta:
                    type: 'null'
  /analyze/bulk:
    post:
      tags:
      - Analysis
      summary: Submit bulk domain analysis (results emailed)
      description: 'Submit a large domain list for asynchronous analysis with email delivery.


        Unlike /analyze/batch ( dispatch -> settle sequence runs in ``process_bulk_job`` with the

        same post-dispatch billing settlement as the batch pass 3, and when every

        child job is terminal the hygiene tick flips the row to ``exporting`` so

        the export task renders CSV/JSON, uploads to S3, and emails presigned

        links to the account address. Invalid domains are recorded as per-item

        errors on the bulk job (batch precedent), not a whole-request 422.'
      operationId: submit_bulk_analysis_analyze_bulk_post
      parameters:
      - name: X-API-Key
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: X-Api-Key
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/BulkSubmitRequest'
      responses:
        '202':
          description: Bulk submission accepted
          content:
            application/json:
              schema: {}
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '401':
          description: Unauthorized — missing or invalid API key/JWT.
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: 'null'
                  error:
                    type: object
                    properties:
                      code:
                        type: string
                        example: UNAUTHORIZED
                      message:
                        type: string
                  meta:
                    type: 'null'
components:
  schemas:
    ValidationError:
      properties:
        loc:
          items:
            anyOf:
            - type: string
            - type: integer
          type: array
          title: Location
        msg:
          type: string
          title: Message
        type:
          type: string
          title: Error Type
        input:
          title: Input
        ctx:
          type: object
          title: Context
      type: object
      required:
      - loc
      - msg
      - type
      title: ValidationError
    ErrorDetail:
      properties:
        code:
          type: string
          title: Code
        message:
          type: string
          title: Message
        details:
          anyOf:
          - additionalProperties: true
            type: object
          - type: 'null'
          title: Details
      type: object
      required:
      - code
      - message
      title: ErrorDetail
      description: "Structured error information for API error responses.\n\nAttributes:\n    code: Machine-readable error code (e.g. \"JOB_NOT_FOUND\").\n    message: Human-readable error description.\n    details: Optional additional context for debugging."
      example:
        code: JOB_NOT_FOUND
        message: No job found with the given ID.
    ApiResponse_SubmitResponse_:
      properties:
        data:
          anyOf:
          - $ref: '#/components/schemas/SubmitResponse'
          - type: 'null'
        error:
          anyOf:
          - $ref: '#/components/schemas/ErrorDetail'
          - type: 'null'
        meta:
          anyOf:
          - additionalProperties: true
            type: object
          - type: 'null'
          title: Meta
      type: object
      title: ApiResponse[SubmitResponse]
    SubmitResponse:
      properties:
        job_id:
          type: string
          title: Job Id
        domain:
          type: string
          title: Domain
        display_domain:
          type: string
          title: Display Domain
          default: ''
        status:
          type: string
          enum:
          - pending
          - processing
          - completed
          - failed
          - partial
          title: Status
        deduplicated:
          type: boolean
          title: Deduplicated
          default: false
        analysis_run_id:
          anyOf:
          - type: string
          - type: 'null'
          title: Analysis Run Id
        charge:
          anyOf:
          - $ref: '#/components/schemas/AnalysisCharge'
          - type: 'null'
      type: object
      required:
      - job_id
      - domain
      - status
      title: SubmitResponse
      description: "Response after submitting a domain for analysis.\n\nAttributes:\n    job_id: Unique job identifier for polling status.\n    domain: The domain submitted (normalized).\n    status: Initial job status (typically \"pending\").\n    deduplicated: True if an existing active job was returned.\n    analysis_run_id: Database analysis run ID (None if deduplicated)."
      example:
        analysis_run_id: 660e8400-e29b-41d4-a716-446655440001
        deduplicated: false
        display_domain: example.com
        domain: example.com
        job_id: 550e8400-e29b-41d4-a716-446655440000
        status: pending
    JobStatusResponse:
      properties:
        job_id:
          type: string
          title: Job Id
        status:
          type: string
          enum:
          - pending
          - processing
          - completed
          - failed
          - partial
          title: Status
        domain:
          anyOf:
          - type: string
          - type: 'null'
          title: Domain
        phase:
          anyOf:
          - type: string
          - type: 'null'
          title: Phase
        collectors_done:
          anyOf:
          - type: integer
          - type: 'null'
          title: Collectors Done
        collectors_total:
          anyOf:
          - type: integer
          - type: 'null'
          title: Collectors Total
        analysis_run_id:
          anyOf:
          - type: string
          - type: 'null'
          title: Analysis Run Id
        started_at:
          anyOf:
          - type: string
          - type: 'null'
          title: Started At
        completed_at:
          anyOf:
          - type: string
          - type: 'null'
          title: Completed At
        scoring_result:
          anyOf:
          - additionalProperties: true
            type: object
          - type: 'null'
          title: Scoring Result
      type: object
      required:
      - job_id
      - status
      title: JobStatusResponse
      description: "Response for polling a job's current status.\n\nWhen the job is completed, ``scoring_result`` contains the full\nScoringResult dict from the scoring engine.\n\nWhen LLM enrichment is enabled and the ambiguity gate triggers,\nthe scoring_result dict includes additional fields:\nenriched_conclusion, entity_resolution_notes, arbitration_reasoning.\nThese fields are null/absent when LLM was not invoked.\n\nAttributes:\n    job_id: Unique job identifier.\n    status: Current job status (pending, processing, completed, failed).\n    domain: Domain being analyzed.\n    collectors_done: Number of collectors that have finished.\n    collectors_total: Total number of collectors in the pipeline.\n    analysis_run_id: Database analysis run ID.\n    started_at: ISO 8601 timestamp when the job started processing.\n    completed_at: ISO 8601 timestamp when the job finished.\n    scoring_result: Full scoring result dict when completed. May include\n        enriched_conclusion, entity_resolution_notes, and\n        arbitration_reasoning when LLM enrichment was invoked."
      example:
        analysis_run_id: 660e8400-e29b-41d4-a716-446655440001
        collectors_done: 3
        collectors_total: 7
        domain: example.com
        job_id: 550e8400-e29b-41d4-a716-446655440000
        started_at: '2026-03-18T12:00:00Z'
        status: processing
    AnalysisCharge:
      properties:
        credits:
          type: integer
          title: Credits
        reason:
          type: string
          enum:
          - analysis
          - overage
          - recently_analyzed_free
          - uncharged
          title: Reason
      type: object
      required:
      - credits
      - reason
      title: AnalysisCharge
      description: 'What this submission cost, for legible billing (Dissent 1).


        ``credits`` is the number debited (0 for a free dedup-follower or an

        uncharged race). ``reason`` is the API-facing explanation -- note it is

        NOT the ledger''s ``LedgerReason`` (a follower bills 0 here as

        ``recently_analyzed_free`` while the ledger row is ``follower_free``).'
    SubmitRequest:
      properties:
        domain:
          type: string
          maxLength: 512
          minLength: 1
          title: Domain
          description: Domain name to analyze (ASCII or internationalized).
        display_domain:
          type: string
          title: Display Domain
          description: Original IDN form of the domain (populated internally).
          default: ''
        depth:
          type: string
          enum:
          - deep
          - quick
          title: Depth
          description: Analysis depth. 'deep' (default) queues the full async pipeline (all collectors, vision, LLM enrichment, metered third-party enrichment) and returns 202 + job_id for polling. 'quick' runs the fast collector subset (dns/whois/http_probe/asn/rdns) inline under a hard deadline and returns 200 with the terminal result plus job_id; it never runs vision/LLM/reverse-WHOIS/metered enrichment. 'quick' cannot be combined with force_refresh or wait=true (400).
          default: deep
        force_refresh:
          type: boolean
          title: Force Refresh
          default: false
        callback_url:
          anyOf:
          - type: string
            maxLength: 2048
            pattern: ^https?://
          - type: 'null'
          title: Callback Url
          description: Optional URL to receive a webhook POST when analysis completes
        output_schema:
          anyOf:
          - type: string
            format: uuid
          - type: 'null'
          title: Output Schema
          description: Template ID for response projection (mutually exclusive with output_fields)
        output_fields:
          anyOf:
          - $ref: '#/components/schemas/OutputFieldsSpec'
          - type: 'null'
          description: Inline field spec for response projection (mutually exclusive with output_schema)
      type: object
      required:
      - domain
      title: SubmitRequest
      description: "Request body for submitting a single domain for analysis.\n\nAttributes:\n    domain: Fully qualified domain name to analyze.\n    force_refresh: Skip dedup and force a fresh analysis run."
      example:
        callback_url: https://example.com/webhook
        domain: example.com
        force_refresh: false
    ApiResponse_JobStatusResponse_:
      properties:
        data:
          anyOf:
          - $ref: '#/components/schemas/JobStatusResponse'
          - type: 'null'
        error:
          anyOf:
          - $ref: '#/components/schemas/ErrorDetail'
          - type: 'null'
        meta:
          anyOf:
          - additionalProperties: true
            type: object
          - type: 'null'
          title: Meta
      type: object
      title: ApiResponse[JobStatusResponse]
    HTTPValidationError:
      properties:
        detail:
          items:
            $ref: '#/components/schemas/ValidationError'
          type: array
          title: Detail
      type: object
      title: HTTPValidationError
    BatchSubmitRequest:
      properties:
        domains:
          items:
            type: string
          type: array
          maxItems: 50
          minItems: 1
          title: Domains
        depth:
          type: string
          enum:
          - deep
          - quick
          title: Depth
          description: Analysis depth, applied to every domain in the batch. 'deep' (default) queues full async analyses (202/207/422). 'quick' runs each domain through the inline fast path (same semantics as POST /analyze depth=quick) and is capped at 10 domains per batch (422 above) so the request stays under the edge timeout; it cannot be combined with force_refresh (400).
          default: deep
        force_refresh:
          type: boolean
          title: Force Refresh
          default: false
        callback_url:
          anyOf:
          - type: string
            maxLength: 2048
            pattern: ^https?://
          - type: 'null'
          title: Callback Url
          description: Optional URL to receive webhook POSTs when each analysis completes
        output_schema:
          anyOf:
          - type: string
            format: uuid
          - type: 'null'
          title: Output Schema
          description: Template ID for response projection (mutually exclusive with output_fields)
        output_fields:
          anyOf:
          - $ref: '#/components/schemas/OutputFieldsSpec'
          - type: 'null'
          description: Inline field spec for response projection (mutually exclusive with output_schema)
      type: object
      required:
      - domains
      title: BatchSubmitRequest
      description: "Request body for submitting multiple domains for analysis.\n\nAttributes:\n    domains: List of domain names to analyze (1-50)."
    BulkSubmitRequest:
      properties:
        domains:
          items:
            type: string
          type: array
          maxItems: 500
          minItems: 1
          title: Domains
        force_refresh:
          type: boolean
          title: Force Refresh
          default: false
      type: object
      required:
      - domains
      title: BulkSubmitRequest
      description: "Request body for a bulk domain upload (results delivered by email).\n\nAttributes:\n    domains: List of domain names to analyze (1-500; the operator-tunable\n        cap ``settings.bulk_max_domains`` is enforced by the handler).\n    force_refresh: Skip deduplication, force fresh analysis runs."
    OutputFieldsSpec:
      properties:
        mode:
          type: string
          enum:
          - include
          - exclude
          title: Mode
        fields:
          items:
            type: string
          type: array
          minItems: 1
          title: Fields
      type: object
      required:
      - mode
      - fields
      title: OutputFieldsSpec
      description: "Inline field projection spec for response customization.\n\nSpecifies a mode (include or exclude) and a list of dot-notation field\npaths to apply as a filter on the scoring_result dict.\n\nAttributes:\n    mode: ``\"include\"`` to whitelist fields, ``\"exclude\"`` to blacklist.\n    fields: List of dot-notation field paths (min 1 required)."
  securitySchemes:
    HTTPBearer:
      type: http
      scheme: bearer