Lookups
Look up IP addresses and domains, and check your account and the API's health.
lookup_ip
Returns intelligence for an IPv4 or IPv6 address, given as a string or an ipaddress object.
def lookup_ip(self, ip: str | IPv4Address | IPv6Address) -> IPInfo
async def lookup_ip(self, ip: str | IPv4Address | IPv6Address) -> IPInfo
info = client.lookup_ip("213.149.183.127")
if info.location is not None:
print(info.location.city, info.location.country)
if info.intelligence is not None:
for provider in info.intelligence.providers:
print(provider.name, provider.type, provider.last_seen)
- Cost: Each lookup costs one credit, and failed lookups are not billed.
- Input: An invalid address raises
ValueError, and a value that is not a string or anipaddressobject raisesTypeError, without sending a request. - Errors: Private and reserved addresses raise an
APIErrorwith status 422.
lookup_ips
Looks up as many as 1000 addresses in one request.
def lookup_ips(self, ips: Iterable[str | IPv4Address | IPv6Address]) -> list[IPInfo]
async def lookup_ips(self, ips: Iterable[str | IPv4Address | IPv6Address]) -> list[IPInfo]
results = client.lookup_ips(["8.8.8.8", "1.1.1.1"])
for result in results:
if result.intelligence is None:
print(result.ip, "no intelligence available")
continue
print(result.ip, result.intelligence.risk_score)
- Cost: The API bills
ceil(n * 0.9)credits for thendistinct usable addresses it looks up, and bills nothing if the account cannot cover the whole batch. - Results: Private and reserved addresses are skipped without a result and duplicates collapse into one, so there can be fewer results than addresses. Results follow the order in which each address first appears, but match them by
IPInfo.iprather than by position. - Input: An empty iterable returns
[]without a request. An invalid address, or more than 1000 addresses, raisesValueErrorbefore anything is sent. - Errors: A batch in which every address is private or reserved raises an
APIErrorwith status 422.
lookup_domain
Returns the honeypot traffic Synthient has observed for a domain.
def lookup_domain(self, domain: str, *, limit: int | None = None) -> DomainInfo
async def lookup_domain(self, domain: str, *, limit: int | None = None) -> DomainInfo
- Name
limit- Type
- int | None
- Description
Caps the number of recent events returned, from 1 to 1000.
Noneuses the API default of 50. A value below 1, or one that is not an integer, raisesValueError.
domain = client.lookup_domain("example.com", limit=10)
print(domain.status, domain.stats.events_24h)
for event in domain.recent_events:
print(event.timestamp, event.target_subdomain, event.port)
- Cost: Each lookup costs one credit.
- Rate limit: The API allows 20 per minute per team.
- Input: Internationalized names must be sent in Punycode. An empty domain,
".", or".."raisesValueErrorwithout a request. - Results: A domain that has never been observed returns
status"inactive"with zeroed stats rather than an error.
Account and health
account
Returns the account that owns the API key, including its scopes and remaining lookup credits.
def account(self) -> Account
async def account(self) -> Account
from datetime import timedelta
account = client.account()
print(account.email, account.organization.name, account.scopes)
quota = account.lookup_quota
print(quota.credits, "credits, resetting in", timedelta(seconds=quota.resets_in))
- Cost: It costs no credits.
health
Returns None if the API and its dependencies are healthy.
def health(self) -> None
async def health(self) -> None
client.health()
- Cost: It costs no credits.
- Errors: An unhealthy API raises an
APIErrorwith status 503, which is not retried. The API does not check the key, but a malformed key raises anAPIErrorwith status 401.