Lookups

View as markdown

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.

pub async fn lookup_ip(&self, ip: impl Into<IpAddr>) -> Result<IpInfo>
use std::net::IpAddr;

let ip: IpAddr = "213.149.183.127".parse()?;
let info = client.lookup_ip(ip).await?;
if let Some(location) = &info.location {
    println!("{} {}", location.city, location.country);
}
if let Some(intelligence) = &info.intelligence {
    for provider in &intelligence.providers {
        println!(
            "{} {} {:?}",
            provider.name,
            provider.r#type,
            provider.last_seen.to_system_time()
        );
    }
}
  • Cost: Each lookup costs one credit, and failed lookups are not billed.
  • Input: It accepts anything that converts into IpAddr, such as Ipv4Addr or Ipv6Addr; parse untrusted strings into an IpAddr first.
  • Errors: Private and reserved addresses return a 422 Error::Api.

lookup_ips

Looks up as many as 1000 addresses in one request.

pub async fn lookup_ips(&self, ips: &[IpAddr]) -> Result<Vec<IpInfo>>
let ips = ["8.8.8.8".parse()?, "1.1.1.1".parse()?];
for result in client.lookup_ips(&ips).await? {
    match &result.intelligence {
        Some(intelligence) => println!("{} {}", result.ip, intelligence.risk_score),
        None => println!("{} no intelligence available", result.ip),
    }
}
  • Cost: The API bills ceil(n * 0.9) credits for the n distinct addresses it looks up, and bills nothing if the account cannot cover the whole batch.
  • Results: Private and reserved addresses are skipped and duplicates collapse into one result, so there can be fewer results than addresses. Match results by IpInfo::ip rather than by index.
  • Input: An empty slice returns an empty Vec without a request. More than 1000 addresses return Error::InvalidInput before anything is sent.
  • Errors: A batch with no address the API can look up returns a 422 Error::Api.

lookup_domain

Returns the honeypot traffic Synthient has observed for a domain.

pub async fn lookup_domain(&self, domain: &str, limit: Option<u32>) -> Result<DomainInfo>
let domain = client.lookup_domain("example.com", Some(10)).await?;
println!("{} {}", domain.status, domain.stats.events_24h);
for event in &domain.recent_events {
    println!(
        "{:?} {} {}",
        event.timestamp.to_system_time(),
        event.target_subdomain,
        event.port
    );
}
  • Cost: Each lookup costs one credit.
  • Input: limit caps the number of recent events returned, from 1 to 1000, and None uses the API default of 50. Internationalized names must be sent in Punycode. An empty domain, ".", or ".." returns Error::InvalidInput without a request.
  • Results: A domain that has never been observed returns DomainStatus::Inactive and zero counts rather than an error.

Account and health

account

Returns the account that owns the API key, including its scopes and remaining lookup credits.

pub async fn account(&self) -> Result<Account>
use synthient::Scope;

let account = client.account().await?;
let scopes: Vec<&str> = account.scopes.iter().map(Scope::as_str).collect();
println!(
    "{} {} {}",
    account.email,
    account.organization.name,
    scopes.join(", ")
);
println!(
    "{} credits, resetting in {} seconds",
    account.lookup_quota.credits, account.lookup_quota.resets_in
);
  • Cost: It costs no credits.

health

Returns Ok(()) if the API and its dependencies are healthy.

pub async fn health(&self) -> Result<()>
client.health().await?;
  • Cost: It costs no credits.
  • Retries: Like the billed lookups, it is retried only on 429 responses that carry Retry-After, so an unhealthy API is reported at once.
  • Errors: An unhealthy API returns a 503 Error::Api. The API does not check the key, but a malformed key returns a 401 Error::Api.