跳到正文
DEV Community· IP99·· 4 小時前AI 評分39

IP99 OpenAPI 一次匯入:Postman、程式碼生成與 GPT Actions

Import IP99's OpenAPI Once: Postman, Codegen, and GPT Actions

AI 導讀

IP99 提供穩定網址的 OpenAPI 3.1.0 文件,可匯入 Postman、Insomnia、openapi-generator 或 GPT Actions,涵蓋免費查詢、配額及需專業密鑰的 Pulse 路徑。匿名配額目前為每個客戶端 IP 每日 500 次、每分鐘 60 次;配額可能變動,應以回應標頭或 /v1/me 為準。

正文

Most IP-risk vendors hand you a PDF and a support ticket. IP99 by ThreatHunter publishes an OpenAPI 3.1 document at a stable URL you can import the same way you import any other public API: Postman, Insomnia, openapi-generator, or a GPT Action. One file describes the free profile, the quota endpoint, and the professional Pulse path — so your clients, types, and agent tools stay in sync with the live service instead of a blog post you copied six months ago.

This is a practical import walkthrough. Every curl below runs without an API key. Live samples were captured on 2026-10-31 (UTC).

What the spec actually covers

curl -s https://ip99.com/openapi.json | head -c 200
# → {"openapi":"3.1.0","info":{"title":"IP99 IP risk and geolocation API",...

As of today the document advertises OpenAPI 3.1.0, title IP99 IP risk and geolocation API, version 1.0.0, server https://ip99.com, and three paths:

Path What it is
GET /v1/ip/{ip} Free risk + geo + network profile (key optional)
GET /v1/me Your current tier and remaining quota
GET /pulse/v1/ip/{ip} Same score with per-evidence detail (professional key)

Access-Control-Allow-Origin: * is set on the OpenAPI JSON itself, so browser-based importers and GPT Action validators can fetch it without a CORS proxy. Security schemes in the file are exactly what the human docs say: X-API-Key header or Authorization: Bearer, never a query string (?key= is rejected with HTTP 400 key_in_query).

The free endpoint is still the one you should try first:

curl https://ip99.com/v1/ip/8.8.8.8

Captured ~2026-10-31 13:05 UTC:

{
  "ip": "8.8.8.8",
  "computed_at": "2026-10-31T13:05:33Z",
  "evidence_state": "none",
  "geo": {
    "continent": "NA",
    "country": "US",
    "region": "California",
    "city": "Mountain View",
    "district": "",
    "tz": "America/Los_Angeles"
  },
  "network": { "asn": 15169, "usage_type": "IDC" },
  "risk": {
    "score": 0,
    "level": "none",
    "signals": ["hosting"]
  }
}

hosting here is a network attribute, not a risk verdict. Score 0 with evidence_state: none means "no current verifiable evidence," not "safe." Official copy is blunt about that; your generated client should expose evidence_state as a first-class field, not bury it under "extra."

Import into Postman (or Insomnia)

  1. Copy https://ip99.com/openapi.json.
  2. Postman: Import → Link → paste the URL → Import. Insomnia: Create → Import From → URL.
  3. You get three requests. Open lookupIP (GET /v1/ip/{ip}), set ip to 8.8.8.8, send. No Authorization needed for anonymous quota.
  4. Optional: add a collection variable apiKey and map it to the apiKey / bearer scheme when you create a free key in the console. Fields do not change with a key — only the quota counter does.

Anonymous allowance today (from GET /v1/me): 500 lookups/day per client IP, 60/min, resetting at midnight Asia/Shanghai. Sign in and self-create a key for a higher daily bucket; overseas self-serve Pro / Pro+ buys volume, not a different score. Per-item evidence rows, share_tier, and ?at= history sit on Pulse and need a professional key.

Generate a typed client

Any OpenAPI 3.1 generator that understands 3.1 will work. Example with the official CLI (install once, then pin the URL):

npx @openapitools/openapi-generator-cli generate \
  -i https://ip99.com/openapi.json \
  -g typescript-fetch \
  -o ./ip99-client

Or Python:

openapi-generator-cli generate \
  -i https://ip99.com/openapi.json \
  -g python \
  -o ./ip99-py

What you should assert in a smoke test after generation:

  1. Response type includes evidence_state enum: active | stale | none.
  2. risk.score is documented (and treated in app code) as freshness/strength of evidence, not "probability this visitor is an attacker."
  3. risk.signals is an array of slugs; hosting / mobile describe the network and are not, by themselves, a ban reason.
  4. Errors are { "error": { "code", "message" } } — branch on error.code, never on the prose in message.

A second live call, using IP99's documented demo address (mask the last octet of real customer IPs in tickets):

curl https://ip99.com/v1/ip/27.22.66.200

Same window:

{
  "ip": "27.22.66.200",
  "computed_at": "2026-10-31T13:05:57Z",
  "evidence_state": "active",
  "geo": {
    "country": "CN",
    "region": "Hubei",
    "city": "Xiangyang",
    "district": "Yicheng",
    "tz": "Asia/Shanghai"
  },
  "network": { "asn": 4134, "usage_type": "DYN" },
  "risk": {
    "score": 7,
    "level": "low",
    "signals": ["dialup_pool", "hijacked_proxy", "proxy"]
  }
}

Residential usage_type: DYN plus proxy-class signals is exactly why "ban all IDC ASN ranges" fails: the interesting exits often sit on home broadband. Official triage order: read evidence_state first, then signals, then score/level — and prefer step-up verification over hard-banning a whole building when the address may be shared.

Wire it as a GPT Action (or similar)

Custom GPTs / Actions that accept an OpenAPI URL can point at the same file. Practical checklist:

  • Schema URL: https://ip99.com/openapi.json (CORS already allows browser fetch).
  • Auth for free experiments: none. For production volume, header X-API-Key.
  • Restrict the Action to GET /v1/ip/{ip} (and maybe /v1/me) unless the agent truly has a professional Pulse key. Leaving Pulse in the Action without a key only produces 403 professional_required noise.
  • Prompt the model to report evidence_state and computed_at alongside the score. A stale or empty evidence state with score 0 must not be summarized as "clean IP."

If you want agents without a custom GPT, IP99 also exposes the same free profile as an MCP tool ip_risk_lookup at https://ip99.com/mcp — same fields as /v1/ip/{ip}. That path is covered in an earlier post; the OpenAPI file remains the right source of truth for HTTP clients and codegen.

Quotas, headers, and what not to invent

Every successful lookup can carry daily quota headers (X-Daily-Limit, X-Daily-Remaining, X-Daily-Reset). Prefer those (or GET /v1/me) over hard-coding numbers from an old article — allowances can change, and the response is authoritative for your tier.

Do not cache risk verdicts across sessions: the product thesis is that every answer is a judgement that expires. computed_at is part of what makes a decision auditable. Pulse's ?at= replay exists for chargeback-style "what did we know then?" questions; the free /v1/ip endpoint answers now only.

Also out of scope for this import guide (and for honest marketing): inventing customer logos, accuracy percentages, funding claims, or equating IP99's free profile with ThreatHunter's full enterprise datasets. IP99 is a ThreatHunter product; the free JSON you get from /v1/ip is exactly what the OpenAPI schema for that path describes — nothing more.

Try it

  1. Import https://ip99.com/openapi.json.
  2. Hit /v1/ip/8.8.8.8 with no key.
  3. Branch your app on evidence_state before you trust a zero.

Human reference: https://ip99.com/api. Product home: https://ip99.com.

來源:DEV Community · dev.to