feat(ipinfo): support the Lite API for free/Lite plan tokens (v1.1.0)
The integration only exposed the Core API (/lookup/*), which returns 403
for accounts on the free/Lite plan — including the instance Test button.
Add the Lite endpoints: lite_lookup_ip (GET /lite/{ip}), lite_lookup_me
(GET /lite/me) and lite_batch (POST /batch/lite, code-first because the
endpoint takes a raw JSON array; chunked at the documented 1000-IP cap).
Point test_connection at /lite/me: every plan can reach it, so the token
check now succeeds on Lite-only accounts while still validating Core ones.
Core commands keep their paths and state the plan requirement up front.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,15 +1,15 @@
|
||||
id: ipinfo
|
||||
name: IPinfo
|
||||
version: 1.0.1
|
||||
description: "IPinfo Core API — IP address enrichment: geolocation, ASN / network details, and privacy/network flags (hosting, mobile, anycast, satellite)."
|
||||
changelog: "1.0.1 — Re-publish to regenerate form-based command scripts (fixes 'script not found' on install). 1.0.0 — Initial release: IP lookup, single-field lookup, own IP, batch, and connectivity test."
|
||||
version: 1.1.0
|
||||
description: "IPinfo — IP address enrichment. Lite API (all plans, unlimited): ASN / AS name / AS domain / country / continent. Core API (paid Core plan): geolocation, network details and privacy flags (hosting, mobile, anycast, satellite)."
|
||||
changelog: "1.1.0 — Lite API support for accounts on the free/Lite plan: lite_lookup_ip, lite_lookup_me and lite_batch (POST /batch/lite, chunked at 1000 IPs). test_connection now calls /lite/me, which every plan can reach, so the Test button no longer fails on Lite-only tokens. Core commands renamed in their description to state the Core plan requirement. 1.0.1 — Re-publish to regenerate form-based command scripts (fixes 'script not found' on install). 1.0.0 — Initial release: IP lookup, single-field lookup, own IP, batch, and connectivity test."
|
||||
category: enrichment
|
||||
|
||||
config_schema:
|
||||
properties:
|
||||
base_url:
|
||||
type: string
|
||||
description: IPinfo Core API base URL
|
||||
description: "IPinfo API base URL (shared by the Lite and Core endpoints)"
|
||||
default: https://api.ipinfo.io
|
||||
token:
|
||||
type: string
|
||||
@@ -28,9 +28,50 @@ auth:
|
||||
secret_field: token
|
||||
|
||||
commands:
|
||||
# ── Lite API — available on every plan, no daily/monthly quota ─────────────
|
||||
- id: lite_lookup_ip
|
||||
name: ipinfo-lite-lookup-ip
|
||||
description: "Lite enrichment for an IP — ASN, AS name, AS domain, country and continent. Works on every plan, including free/Lite."
|
||||
risk: read
|
||||
inputs_schema:
|
||||
properties:
|
||||
ip: { type: string, description: "IPv4 or IPv6 address" }
|
||||
required: [ip]
|
||||
outputs_schema: { properties: {} }
|
||||
request:
|
||||
method: GET
|
||||
path: /lite/{ip}
|
||||
auth_ref: apikey
|
||||
|
||||
- id: lite_lookup_me
|
||||
name: ipinfo-lite-lookup-me
|
||||
description: "Lite details for the IP address making the request (ASN, country, continent)."
|
||||
risk: read
|
||||
inputs_schema:
|
||||
properties: {}
|
||||
required: []
|
||||
outputs_schema: { properties: {} }
|
||||
request:
|
||||
method: GET
|
||||
path: /lite/me
|
||||
auth_ref: apikey
|
||||
|
||||
# Code-first: POST /batch/lite takes a raw JSON array body, which the
|
||||
# form-based generator (object body) cannot produce. See scripts/lite_batch.py.
|
||||
- id: lite_batch
|
||||
name: ipinfo-lite-batch
|
||||
description: "Lite lookup for many IPs in one call. Chunked at the API limit of 1000 IPs per request; returns one object keyed by IP."
|
||||
risk: read
|
||||
inputs_schema:
|
||||
properties:
|
||||
ips: { type: string, description: "Comma-separated IP addresses, e.g. '8.8.8.8,1.1.1.1'" }
|
||||
required: [ips]
|
||||
outputs_schema: { properties: {} }
|
||||
|
||||
# ── Core API — requires a paid Core plan (403 on Lite/free tokens) ─────────
|
||||
- id: lookup_ip
|
||||
name: ipinfo-lookup-ip
|
||||
description: Full enrichment for an IP — geolocation, ASN/network, and privacy/network flags.
|
||||
description: "Core plan required. Full enrichment for an IP — geolocation, ASN/network, and privacy/network flags."
|
||||
risk: read
|
||||
inputs_schema:
|
||||
properties:
|
||||
@@ -44,7 +85,7 @@ commands:
|
||||
|
||||
- id: lookup_field
|
||||
name: ipinfo-lookup-field
|
||||
description: A single field for an IP (e.g. city, country, hostname, as).
|
||||
description: "Core plan required. A single field for an IP (e.g. city, country, hostname, as)."
|
||||
risk: read
|
||||
inputs_schema:
|
||||
properties:
|
||||
@@ -59,7 +100,7 @@ commands:
|
||||
|
||||
- id: lookup_me
|
||||
name: ipinfo-lookup-me
|
||||
description: Details for the IP address making the request.
|
||||
description: "Core plan required. Details for the IP address making the request."
|
||||
risk: read
|
||||
inputs_schema:
|
||||
properties: {}
|
||||
@@ -74,7 +115,7 @@ commands:
|
||||
# form-based generator (object body) cannot produce. See scripts/batch.py.
|
||||
- id: batch
|
||||
name: ipinfo-batch
|
||||
description: Look up multiple IPs (or IP/field paths) in a single request.
|
||||
description: "Core plan required. Look up multiple IPs (or IP/field paths) in a single request."
|
||||
risk: read
|
||||
inputs_schema:
|
||||
properties:
|
||||
@@ -82,6 +123,8 @@ commands:
|
||||
required: [ips]
|
||||
outputs_schema: { properties: {} }
|
||||
|
||||
# Uses the Lite endpoint on purpose: it validates the token on every plan,
|
||||
# whereas /lookup/me returns 403 for Lite-only accounts.
|
||||
- id: test_connection
|
||||
name: ipinfo-test-connection
|
||||
description: "Verify connectivity and credentials (used by the Test button)."
|
||||
@@ -92,5 +135,5 @@ commands:
|
||||
outputs_schema: { properties: {} }
|
||||
request:
|
||||
method: GET
|
||||
path: /lookup/me
|
||||
path: /lite/me
|
||||
auth_ref: apikey
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
import json, os, sys, urllib.request, urllib.parse, urllib.error
|
||||
|
||||
SECRETS = json.loads(os.environ.get("INTEGRATION_SECRETS", "{}"))
|
||||
INPUTS = json.loads(os.environ.get("INTEGRATION_INPUTS", "{}"))
|
||||
BASE = SECRETS.get("base_url", "https://api.ipinfo.io").rstrip("/")
|
||||
|
||||
# IPinfo caps a single Lite batch call at 1000 addresses.
|
||||
CHUNK = 1000
|
||||
|
||||
|
||||
def post_chunk(url, ips):
|
||||
# POST /batch/lite expects a raw JSON array of IPs, not an object.
|
||||
data = json.dumps(ips).encode("utf-8")
|
||||
headers = {"Content-Type": "application/json", "Accept": "application/json"}
|
||||
req = urllib.request.Request(url, data=data, headers=headers, method="POST")
|
||||
with urllib.request.urlopen(req, timeout=30) as r:
|
||||
raw = r.read()
|
||||
return json.loads(raw) if raw else {}
|
||||
|
||||
|
||||
def main():
|
||||
token = SECRETS.get("token", "")
|
||||
seen = set()
|
||||
ips = []
|
||||
for x in str(INPUTS.get("ips", "")).split(","):
|
||||
x = x.strip()
|
||||
if x and x not in seen:
|
||||
seen.add(x)
|
||||
ips.append(x)
|
||||
if not ips:
|
||||
print(json.dumps({"error": "ips is required"}))
|
||||
sys.exit(1)
|
||||
|
||||
url = BASE + "/batch/lite?" + urllib.parse.urlencode({"token": token})
|
||||
result = {}
|
||||
for i in range(0, len(ips), CHUNK):
|
||||
result.update(post_chunk(url, ips[i:i + CHUNK]))
|
||||
print(json.dumps(result))
|
||||
|
||||
|
||||
try:
|
||||
main()
|
||||
except urllib.error.HTTPError as e:
|
||||
print(json.dumps({"error": "HTTP " + str(e.code), "detail": e.read().decode("utf-8", "replace")}))
|
||||
sys.exit(1)
|
||||
except Exception as e:
|
||||
print(json.dumps({"error": str(e)}))
|
||||
sys.exit(1)
|
||||
Reference in New Issue
Block a user