BrumeDomain Intelligence

BrumeDomain Intelligence

API Documentation

Version 1.0 · REST over HTTPS · NDJSON streaming or JSON · 10 requests per minute.

Contents

Introduction

Brume exposes a RESTful API for programmatic domain intelligence. All endpoints are available at https://brume.work/api/v1/

Authentication

No authentication required. Rate limited to 10 scans per minute per IP.

Scan domain

GET /api/v1/scan?domain={domain}

GET /api/v1/scan/{domain}

Scan a domain and return its findings. By default the response is an NDJSON stream of events, one JSON object per line, flushed as each module runs. Send Accept: application/json to receive the complete result once the scan finishes.

Parameters

ParameterTypeRequiredDescription
domainstringyesThe domain to scan, e.g. stripe.com. URLs, ports and trailing dots are accepted and normalised. Passed as the query parameter or the final path segment.

Headers

ParameterTypeRequiredDescription
Acceptstringnoapplication/x-ndjson streams events (default); application/json returns the full result.

Example request

# NDJSON stream (the default)
curl -N "https://brume.work/api/v1/scan?domain=stripe.com"

# Full JSON result (path-parameter variant)
curl -H "Accept: application/json" "https://brume.work/api/v1/scan/stripe.com"

Example response

application/json (excerpt)
{
  "domain": "stripe.com",
  "startedAt": "2026-10-25T14:02:08.114Z",
  "completedAt": "2026-10-25T14:02:22.317Z",
  "progress": {
    "dns": "complete",
    "identity": "complete",
    "http": "complete",
    "infrastructure": "complete"
  },
  "findings": [
    {
      "id": "mx-google",
      "category": "email",
      "service": "Google Workspace",
      "confidence": 0.98,
      "method": "MX record analysis",
      "evidence": ["aspmx.l.google.com", "alt1.aspmx.l.google.com"],
      "tags": ["email", "mx"],
      "url": "https://workspace.google.com"
    }
  ],
  "summary": {
    "totalFindings": 148,
    "highConfidence": 97,
    "categories": { "email": 6, "dns": 24, "identity": 4, "security": 11 },
    "services": ["Amazon Web Services", "Cloudflare", "Google Workspace", "Okta"]
  }
}

The streaming response carries the same data as a sequence of events — see Streaming format.

Status codes

StatusMeaning
200Scan started (stream) or completed (JSON).
400The domain is missing or not a valid hostname.
429Rate limit exceeded — more than 10 requests in a minute.

Health

GET /api/v1/health

Liveness and metadata. Returns the service status, the API version and the detection modules a scan runs.

Example response

{
  "status": "ok",
  "version": "1.0.0",
  "modules": [
    "dns", "dnsDeep", "subdomains", "identity", "http",
    "infrastructure", "endpoints", "attackSurface", "tenants",
    "orgIntel", "apps", "github", "cloudStorage", "wellKnown"
  ]
}

Response schema

Every finding in a report is a Finding:

interface Finding {
  id: string
  category: 'email' | 'dns' | 'identity' | 'infrastructure' | 'saas' | 'security'
  service: string
  confidence: number
  method: string
  evidence: string[]
  tags: string[]
  url?: string
  risk?: string
  metadata?: Record<string, string>
}
FieldTypeDescription
idstringStable identifier, unique within a scan.
categorystringOne of email, dns, identity, infrastructure, saas, security.
servicestringHuman-readable name of the detected service or record.
confidencenumberDetection confidence, 0 to 1.
methodstringHow the finding was detected, e.g. 'MX record analysis'.
evidencestring[]Raw supporting lines: records, headers, hostnames.
tagsstring[]Free-form tags for filtering.
urlstring?Optional link to the detected service.
riskstring?Optional one-line supply-chain risk note.
metadataobject?Optional string key/value map of structured detail.

Streaming format

The default response is newline-delimited JSON: one event object per line, flushed as the scan progresses. Four event types appear.

  • progress — a module changed state (scanning, complete, error).
  • findings — a batch of findings from a module.
  • error — a single module failed; the scan continues.
  • complete — the final result, identical to the JSON response.
NDJSON event stream
{"type": "progress", "module": "dns", "status": "scanning"}
{"type": "findings", "module": "dns", "data": [ ... ]}
{"type": "progress", "module": "dns", "status": "complete"}
{"type": "error", "module": "github", "message": "request timed out"}
{"type": "complete", "data": { ... }}

Modules

A scan runs these detection modules concurrently. The module field on each event names the module, and /health lists them. Further intelligence — security posture, identity chain, network topology, CVE mapping and more — is derived after the modules settle and folded into the final findings.

DNS & Email

dns

Nameservers, registrar, mail exchangers and the SPF, DKIM, DMARC and SOA records that decide who may send as the domain.

Deep DNS

dnsDeep

Records the primary pass omits: SSHFP, DANE/TLSA, OPENPGPKEY, DNSLink, HTTPS/SVCB with ECH, and LOC.

Subdomains

subdomains

Every hostname disclosed in certificate transparency logs, sorted and counted.

Identity

identity

Single sign-on providers, SAML and OIDC endpoints, and the federation path a user takes to sign in.

HTTP

http

Server, framework, CMS and CDN fingerprints drawn from response headers and the landing HTML.

Infrastructure

infrastructure

CDN, hosting provider, WAF, ASN attribution and the live TLS certificate behind the front door.

Endpoints

endpoints

Service endpoints probed on resolved hosts — Grafana, Vault, Teleport, GitLab and similar self-managed tools.

Attack surface

attackSurface

OpenAPI, GraphQL and exposed-path discovery across the subdomains and endpoints found so far.

Tenants

tenants

SaaS workspace and tenant discovery derived from the organisation's slug.

Organisation

orgIntel

Organisation identity: company metadata, GitHub organisation and related slugs.

Mobile apps

apps

Published applications on the App Store and Google Play.

GitHub

github

Public repositories, CI/CD workflow fingerprints and infrastructure signals from the organisation's GitHub presence.

Cloud storage

cloudStorage

Publicly reachable S3, GCS and Azure Blob buckets inferred from the domain and organisation name.

Well-known

wellKnown

`.well-known` resources: security.txt, JWKS, WebFinger, change-password, host-meta, Matrix, NodeInfo and more.

Code examples

curl
# Stream findings as NDJSON
curl -N "https://brume.work/api/v1/scan?domain=stripe.com"

# Wait for the complete result as JSON
curl -H "Accept: application/json" "https://brume.work/api/v1/scan/stripe.com"

# Service health
curl "https://brume.work/api/v1/health"
Python · requests
import requests

resp = requests.get(
    "https://brume.work/api/v1/scan/stripe.com",
    headers={"Accept": "application/json"},
    timeout=60,
)
resp.raise_for_status()
report = resp.json()

for finding in report["findings"]:
    print(finding["service"], finding["confidence"])
JavaScript · fetch
// Read the NDJSON stream line by line.
const res = await fetch(
  "https://brume.work/api/v1/scan?domain=stripe.com",
)

const reader = res.body.getReader()
const decoder = new TextDecoder()
let buffer = ""

while (true) {
  const { value, done } = await reader.read()
  if (done) break
  buffer += decoder.decode(value, { stream: true })

  const lines = buffer.split("\n")
  buffer = lines.pop() ?? ""

  for (const line of lines) {
    if (!line.trim()) continue
    const event = JSON.parse(line)
    console.log(event.type, event.module ?? "")
  }
}
Go · net/http
package main

import (
    "encoding/json"
    "fmt"
    "net/http"
)

func main() {
    req, _ := http.NewRequest("GET",
        "https://brume.work/api/v1/scan/stripe.com", nil)
    req.Header.Set("Accept", "application/json")

    resp, err := http.DefaultClient.Do(req)
    if err != nil {
        panic(err)
    }
    defer resp.Body.Close()

    var report map[string]any
    json.NewDecoder(resp.Body).Decode(&report)

    for _, raw := range report["findings"].([]any) {
        f := raw.(map[string]any)
        fmt.Printf("%s %v\n", f["service"], f["confidence"])
    }
}

Rate limits

The API is limited to 10 requests per minute per IP. Requests beyond the limit receive a 429 Too Many Requests response. Every response carries X-RateLimit-Limit and X-RateLimit-Remaining headers, alongside X-Brume-Version.