Prerequisites
- Go 1.21+ with
ipapi-goinstalled - A free ip-api.io API key
Match typed errors with errors.As
Every typed error embeds *APIError, which carries StatusCode, Message and Body. Match the specific type you care about.
import "errors"
info, err := client.LookupIP(ctx, "8.8.8.8")
if err != nil {
var rateErr *ipapi.RateLimitError
var authErr *ipapi.AuthenticationError
var invErr *ipapi.InvalidRequestError
var srvErr *ipapi.ServerError
switch {
case errors.As(err, &rateErr):
fmt.Printf("quota hit — resets at %d\n", rateErr.Reset)
case errors.As(err, &authErr):
fmt.Println("check your API key")
case errors.As(err, &invErr):
fmt.Println("bad request:", invErr.Message)
case errors.As(err, &srvErr):
fmt.Println("ip-api.io is having trouble, try later")
default:
fmt.Println("transport / decode error:", err)
}
return
}
fmt.Println(info.IP) *APIError — they fall through to the
default branch above.
Handle rate limits with RateLimitError
On HTTP 429 you get *RateLimitError, carrying the x-ratelimit-* header values (-1 when a header is absent). Because the client never retries, Reset tells you when to.
var rateErr *ipapi.RateLimitError
if errors.As(err, &rateErr) {
fmt.Println(rateErr.Limit) // your quota for the window
fmt.Println(rateErr.Remaining) // requests left (0 here)
fmt.Println(rateErr.Reset) // unix timestamp when quota renews
// schedule a retry at rateErr.Reset instead of hammering the API
} Check quota proactively with RateLimit
Read your current limits without triggering a 429, so you can throttle in advance.
rl, _ := client.RateLimit(ctx)
if rl.PlanName != nil {
fmt.Println(*rl.PlanName)
}
fmt.Printf("%d / %d\n", rl.IPAPI.Remaining, rl.IPAPI.Limit)
fmt.Printf("%.1f%% used\n", rl.EmailAPI.UsagePercent) Account usage with UsageSummary
Aggregate usage for the current period — handy for dashboards and internal alerts.
usage, _ := client.UsageSummary(ctx)
fmt.Println(usage.TotalRequests, usage.SuccessfulRequests)
fmt.Println(usage.RateLimitedRequests, usage.QuotaConsumed)
fmt.Println(usage.PeriodStart, usage.PeriodEnd)