Synthient SDK for Go.
go get -u github.com/synthient/go-synthient/v2Requires Go 1.23 or later (real-time streams use iter.Seq2).
All requests are made through a synthient.Client. Create one with your API key:
client := synthient.NewClient(os.Getenv("SYNTHIENT_API_KEY"))Pass nil as the last argument to any method to use default request options, or supply a *synthient.RequestOptions to attach a context for cancellation and timeouts:
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
opts := &synthient.RequestOptions{Context: ctx}client.GetIP returns enrichment data for a single address:
ip, err := client.GetIP("213.149.183.127", nil)
if err != nil {
log.Fatal(err)
}
fmt.Println(ip.Intelligence.RiskScore, ip.Network.Isp, ip.Location.Country)client.GetIPs looks up multiple addresses in one request:
results, err := client.GetIPs([]string{"8.8.8.8", "1.1.1.1"}, nil)
if err != nil {
log.Fatal(err)
}
for _, ip := range results {
fmt.Println(ip.IP, ip.Intelligence.RiskScore)
}client.GetDomain returns traffic statistics, geo distribution, and recent events for a domain:
domain, err := client.GetDomain("google.com", nil)
if err != nil {
log.Fatal(err)
}
fmt.Println(domain.Stats.Events24H, domain.Status)client.GetAccount returns profile and quota details for the authenticated user:
account, err := client.GetAccount(nil)
if err != nil {
log.Fatal(err)
}
fmt.Println(account.Organization.Name, account.LookupQuota.Credits)Stream identifiers: proxies, anonymizers, torrents, honeypot_http, honeypot_https, honeypot_dns, honeypot_adb.
client.FeedSnapshots returns a paginated list of available daily and hourly snapshots, newest-first:
var cursor string
for {
page, err := client.FeedSnapshots("proxies", &synthient.FeedSnapshotsOptions{
Limit: 50,
Cursor: cursor,
}, nil)
if err != nil {
log.Fatal(err)
}
for _, snap := range page.Feeds {
fmt.Println(snap.Kind, snap.ID, snap.SizeBytes)
}
if page.NextCursor == "" {
break
}
cursor = page.NextCursor
}client.FeedSnapshotMeta returns the checksum, row count, byte size, and parquet schema for a snapshot. date accepts "latest", "YYYY-MM-DD", or "YYYY-MM-DD/HH":
meta, err := client.FeedSnapshotMeta("proxies", "latest", nil)
if err != nil {
log.Fatal(err)
}
fmt.Println(meta.Rows, meta.Checksum)
for _, field := range meta.Schema.Fields {
fmt.Println(field.Name, field.Type)
}client.DownloadFeedSnapshot follows the API's 307 redirect and returns a streaming reader for the parquet file. The caller must close it.
Pass a non-nil hour pointer (0–23) to address a specific hourly snapshot within the current UTC day:
// latest hourly
r, err := client.DownloadFeedSnapshot("proxies", "latest", nil, nil)
if err != nil {
log.Fatal(err)
}
defer r.Close()
f, _ := os.Create("proxies-latest.parquet")
defer f.Close()
io.Copy(f, r)// specific hour
hour := 21
r, err := client.DownloadFeedSnapshot("proxies", "2026-05-07", &hour, nil)All stream methods return an iter.Seq2[T, error] that yields one event per NDJSON line. Break out of the loop or cancel the context to stop the stream.
for event, err := range client.StreamProxy(nil) {
if err != nil {
log.Fatal(err)
}
fmt.Println(event.IP, event.Provider, event.CountryCode)
}ProxyEvent fields: IP, Provider, Type, Timestamp, CountryCode, ASN.
for event, err := range client.StreamAnonymizer(nil) {
if err != nil {
log.Fatal(err)
}
fmt.Println(event.RangeStart, event.RangeEnd, event.Type, event.Provider)
}AnonymizerEvent fields: RangeStart, RangeEnd, Provider, Type, Timestamp.
for event, err := range client.StreamTorrent(nil) {
if err != nil {
log.Fatal(err)
}
fmt.Printf("%s %s peers=%d\n", event.InfoHash, event.Name, len(event.Peers))
}TorrentEvent fields: InfoHash, Name, MagnetURI, TotalSize, PieceLength, FileCount, Files, Peers, Timestamp.
for event, err := range client.StreamHeliosHTTP(nil) {
if err != nil {
log.Fatal(err)
}
fmt.Println(event.Details.Method, event.Details.URI, event.Domain)
}HeliosHTTPEvent fields: Timestamp, Domain, Port, TunnelID, Protocol, Details (method, URI, version, headers map), Raw, Meta (pool ID, provider, proxy IP, server).
for event, err := range client.StreamHeliosTLS(nil) {
if err != nil {
log.Fatal(err)
}
if event.Details == nil {
continue // parse failed
}
fmt.Println(event.Domain, event.Details.HandshakeVersion, len(event.Details.CipherSuites))
}HeliosTLSEvent carries the fully parsed ClientHello in Details (*HeliosTLSDetails), which is nil when the sensor could not parse the handshake. Details includes cipher suites, extensions, supported groups, signature algorithms, key share groups, supported versions, and boolean handshake flags (extended_master_secret, renegotiation_info, has_grease, etc.).
client.GRPCSchema uses gRPC server reflection to fetch protobuf file descriptors from grpc.synthient.com:443. Pass nil to resolve all services, or supply a list of fully-qualified service names:
ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
defer cancel()
// all services
result, err := client.GRPCSchema(ctx, nil)
if err != nil {
if msg := synthient.ExplainGRPCError(err); msg != "" {
log.Fatal(msg)
}
log.Fatal(err)
}
for _, svc := range result.Symbols {
fmt.Println(svc)
}
for _, f := range result.DescriptorSet.File {
fmt.Println(f.GetName(), f.GetPackage())
}// specific symbol
result, err := client.GRPCSchema(ctx, &synthient.GRPCSchemaOptions{
Symbols: []string{"synthient.lookup.v1.LookupService"},
})GRPCSchemaResult fields:
| Field | Type | Description |
|---|---|---|
Endpoint |
string |
Normalized address that was queried |
Symbols |
[]string |
Service symbols that were resolved |
DescriptorSet |
*descriptorpb.FileDescriptorSet |
All file descriptors in topological order |
NormalizeGRPCEndpoint and ExplainGRPCError are exported for use in CLI applications that need custom endpoint handling or human-readable error messages.
Note:
GRPCSchemaaddsgoogle.golang.org/grpcandgoogle.golang.org/protobufto your module's dependency graph. If you only need REST API access these are still pulled in transitively, but no gRPC connections are made unless you callGRPCSchema.
Override BaseAPI to point at a self-hosted endpoint:
client := synthient.NewClient("SECRET TOKEN")
client.BaseAPI.Host = "synthient.myserver.com"Set a custom HTTP client for timeouts or proxies:
client.HttpClient = &http.Client{Timeout: 30 * time.Second}