From subpoof
Use the subpoof subdomain-intelligence API at https://api.subpoof.com/v1 - submit and poll subdomain-enumeration scans, read scan results, list newly-registered domains, query the subdomain-label dictionary, pull per-domain scan history, and manage monitoring (watches for cert/domain expiry and brand lookalikes, outbound webhooks, and recurring scan schedules). Use when the user wants to enumerate a domain's subdomains, check what changed for a domain, find newly-registered domains for a TLD, set up monitoring or alerts for a domain or brand, or otherwise work with subpoof programmatically.
How this skill is triggered — by the user, by Claude, or both
Slash command
/subpoof:subpoofThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
subpoof is a subdomain-enumeration and domain-monitoring service. This skill
subpoof is a subdomain-enumeration and domain-monitoring service. This skill
drives its public JSON API. The full machine-readable contract is the OpenAPI
spec at https://api.subpoof.com/v1/openapi.json - fetch it when you need exact
parameter names or schemas; this file covers the workflows and the conventions
the spec does not spell out.
Every request authenticates with the X-API-Key header. The key is on the
account's dashboard Settings page; treat it as a secret and never log it.
Read it from the SUBPOOF_API_KEY environment variable. If it is not set, stop
and ask the user for their key rather than guessing or calling unauthenticated.
curl -sS https://api.subpoof.com/v1/registrations \
-H "X-API-Key: $SUBPOOF_API_KEY"
Base URL: https://api.subpoof.com/v1. HTTPS only.
These hold across every endpoint - rely on them instead of re-deriving per call.
{
"data": [ ... ],
"pagination": {
"page": 1, "page_size": 25, "total_pages": 7,
"has_next": true, "has_prev": false
}
}
Pagination params: page (1-indexed, default 1) and page_size
(default 25, max 100). To walk every page, loop while pagination.has_next
is true, incrementing page. Do not hardcode a page count.
Any non-2xx returns:
{ "error": { "code": "bad_request", "message": "...", "request_id": "req_..." } }
The request_id also rides on the X-Request-ID response header - capture it
when surfacing an error to the user.
| HTTP | code | Meaning / what to do |
|---|---|---|
| 400 | bad_request | Bad input. Fix the field named in message; do not retry as-is. |
| 401 | unauthenticated | Missing/invalid X-API-Key. Ask the user to check their key. |
| 404 | not_found | No such resource (or not visible to this key). |
| 409 | conflict | Resource not in a usable state yet (e.g. scan not complete). |
| 429 | rate_limited | Monthly query quota reached. See rate limits below. Do NOT loop-retry. |
Successful calls return X-RateLimit-Limit, X-RateLimit-Remaining, and
X-RateLimit-Reset (an ISO date - the quota resets on the 1st of next month).
A 429 rate_limited means the monthly quota is spent; back off and tell the
user, do not spin-retry. Polling a scan's status (GET) is cheap, but be
considerate: poll on an interval (see below), not in a tight loop.
This is the most common task. Submit, poll until complete, then read results.
POST /v1/scanscurl -sS -X POST https://api.subpoof.com/v1/scans \
-H "X-API-Key: $SUBPOOF_API_KEY" \
-H "Content-Type: application/json" \
-d '{"domain": "example.com"}'
Returns 202 with a job_id:
{ "job_id": "...", "domain": "example.com", "status": "pending",
"created_at": "...", "idempotent": false }
Idempotency: re-submitting the same domain on the same calendar day returns the
existing job (200, "idempotent": true) and does not consume another credit.
So it is safe to re-run a submit without double-charging.
Optional enrichments object tunes what the scan collects. Omit it entirely to
get the sensible defaults (all on). Every flag defaults to true:
{
"domain": "example.com",
"enrichments": {
"dns_enrich": true, "ms_tenant": true, "ntlm_probe": true,
"rbl_check": true, "tls_port_check": true, "tls_cert_enum": true,
"lookalike_check": true, "http_fingerprint": true, "email_security": true,
"dict_probe": { "enabled": true, "count": 100, "offset": 0 }
}
}
dict_probe may be a bool (shorthand for enabled/disabled at defaults) or an
object: count is how many dictionary labels to probe (1-1000, default 100),
offset lets you page deeper into the label list on a later scan. To run a fast
scan, set the heavy flags to false and dict_probe.enabled to false.
GET /v1/scans/{job_id}curl -sS https://api.subpoof.com/v1/scans/$JOB_ID -H "X-API-Key: $SUBPOOF_API_KEY"
status moves through: pending -> claimed -> running -> complete
(terminal), or error / stopped (terminal). Poll roughly every 5-10s; a scan
typically takes from tens of seconds to a few minutes depending on enrichments.
When status is complete the response includes subdomain_count,
a signal_summary (counts of notable indicators found), and results_url.
Stop polling on any terminal status. On error, surface the error field.
GET /v1/scans/{job_id}/resultscurl -sS "https://api.subpoof.com/v1/scans/$JOB_ID/results?page=1&page_size=100" \
-H "X-API-Key: $SUBPOOF_API_KEY"
Returns 409 conflict if the job is not complete yet - poll first. Paginated
like any list endpoint. Pass category to fetch only one slice of the findings
(e.g. subdomains, tls_certs, lookalikes, ntlm) instead of the full set.
GET /v1/scans - list past scansFilter with status and/or exact domain. Paginated. Use this to find a prior
job_id or summarize recent activity.
GET /v1/registrations - newly-registered domainsA daily feed of freshly-registered domains. Filter with q (domain PREFIX
match, e.g. q=paypal matches paypal-login.com but not secure-paypal.com),
tld (with or without the leading dot, e.g. .com or com), and a
date_from/date_to range (inclusive, YYYY-MM-DD). Paginated.
Coverage: this feed is generic-TLD (gTLD) only, sourced from ICANN CZDS zone files (.com, .org, .xyz, .app, ...). Country-code TLDs such as .io, .co, and .ai are not included, so filtering to a ccTLD returns no results. Do not tell the user a ccTLD will appear later; it will not come through this feed.
GET /v1/dictionary - subdomain-label dictionaryThe account's ranked subdomain-label dictionary (labels seen across prior
scans). Filter with q (label substring), domain_filter (labels seen on one
root domain), category, or monitored (yes/no). Paginated.
GET /v1/domains/{domain}/history - per-domain timelineThe scan-history timeline for a domain, each entry diffed against the prior
scan - what subdomains appeared or disappeared over time. The oldest scan is
returned as a baseline entry (no diff), so a domain with a single scan still
returns one row rather than an empty timeline.
GET /v1/account - plan and quota standingReturns plan, limit, used, remaining, and resets_on (limit and
remaining are -1 when unlimited). Read this to check headroom before
spending quota; it is never charged.
These surfaces manage standing configuration. None of them consume a query credit - the monthly quota meters intelligence reads and scans, not your monitoring setup. Everything is scoped to the account's org.
/v1/watchesStanding monitors the service checks daily. GET /v1/watches lists them
(filter by type); POST /v1/watches creates one; GET/DELETE /v1/watches/{id} fetch and remove. Types: cert_expiry, domain_expiry,
domain_changes, label, lookalike (all take a target domain/brand), and
dict_search (no target - set at least one of q, domain_filter,
category, monitored). threshold_days (1-365, default 30) sets how many
days before expiry an expiry watch alerts. Creating is idempotent on type +
target (201 new, 200 if it already existed).
/v1/webhookOne outbound webhook per account; the service POSTs HMAC-signed JSON when events
fire. GET /v1/webhook returns the config including the signing secret (used
to verify deliveries); PUT /v1/webhook creates/updates (url, enabled,
event_types); DELETE /v1/webhook removes it. Also POST /v1/webhook/rotate
(new secret), POST /v1/webhook/test (queue a test event),
GET /v1/webhook/deliveries (delivery log), and
POST /v1/webhook/deliveries/{id}/redeliver (retry a dead one). Updating
preserves the secret; rotate to change it. Event types: scan.completed,
watch.alert, domain.changes_detected, label.new_domain,
dict_search.new_label, lookalike.registered (omit event_types for all).
/v1/schedulesRecurring scans. GET /v1/schedules lists; POST /v1/schedules creates
(domain, period: daily/weekly/monthly, optional inherit_from_job to reuse
an existing job's enrichments); GET/DELETE /v1/schedules/{id}; and
POST /v1/schedules/{id}/toggle to pause/resume. Idempotent on domain + period.
Each scan a schedule spawns charges a credit when it runs, like a manual scan.
POST /v1/scans/{job_id}/reanalyze re-runs identity + blocklist checks on a
completed scan's existing subdomain set (no re-enumeration);
POST /v1/scans/{job_id}/rbl-check refreshes only the mail-host DNSBL status.
Both return a new job_id to poll and reuse an in-flight re-run if one exists.
POST /v1/dictionary/monitor with {"label": "..."} toggles a label's pinned
state, or pass "monitored": true|false to set it explicitly.
SUBPOOF_API_KEY from the environment; never invent a key, never echo it.429, stop and report the quota is spent and when it resets; do not retry.https://api.subpoof.com/v1/openapi.json rather than guessing.Provides CDSS development patterns for drug interaction checking, dose validation, clinical scoring (NEWS2, qSOFA), and alert classification integrated into EMR workflows.
npx claudepluginhub jabreity/subpoof-skill --plugin subpoof