Go SDK
The HostRepute Go client, version 0.1.0, wraps the REST API v1 with typed request and response structs, a
context.Context on every call, automatic retries and helpers that start a check and wait for its result. It uses only
the Go standard library and needs Go 1.23 or later.
Install
Section titled “Install”go get github.com/hostrepute/hostrepute-goCreate a client
Section titled “Create a client”hostrepute.New takes a team API token and any number of options. Create the token in
Settings, then API tokens with the abilities your program
needs; Authentication and API tokens explains them. The SDK doesn’t read environment
variables itself: the examples on this page read the token from HOSTREPUTE_API_TOKEN.
package main
import ( "context" "fmt" "log" "os" "time"
hostrepute "github.com/hostrepute/hostrepute-go")
func main() { client, err := hostrepute.New(os.Getenv("HOSTREPUTE_API_TOKEN"), hostrepute.WithTimeout(45*time.Second), hostrepute.WithUserAgent("deploy-checks/1.4"), ) if err != nil { log.Fatal(err) }
ctx := context.Background() for host, err := range client.Hosts.Iterate(ctx, &hostrepute.HostListParams{PerPage: hostrepute.Int(100)}) { if err != nil { log.Fatal(err) } fmt.Println(host.Host, host.IsBlocklisted()) }}New returns an error for an empty token, a base URL without a scheme or host, a timeout of zero or less, or an
invalid retry setting.
| Option | Default | What it does |
|---|---|---|
WithBaseURL(url) |
https://app.hostrepute.com |
The API’s address. Give the origin only: the SDK adds /api/v1/… to every path. |
WithTimeout(d) |
30 seconds | The time limit for each HTTP request. Ignored when you pass WithHTTPClient. |
WithHTTPClient(c) |
&http.Client{Timeout: 30 * time.Second} |
Your own *http.Client, for proxies, custom transports or instrumentation. The SDK uses it as is. |
WithUserAgent(s) |
hostrepute-go/0.1.0 (go) |
The User-Agent header. |
WithRetry(cfg) |
3 attempts, 200 ms base delay, 5 s maximum | The retry policy. See retries. |
WithDefaultHeader(name, value) |
none | An extra header on every request. It can’t replace Authorization, Accept, Content-Type or User-Agent. |
WithLogger(l) |
none | Any logger with Debug, Info, Warn and Error methods, such as *slog.Logger. The SDK logs each request and response at debug level, never the token. |
Resources
Section titled “Resources”The client has one field per API resource. The names follow the API, not the portal:
| In HostRepute | Field | Methods | API |
|---|---|---|---|
| Domains and IPs | client.Hosts |
List, Iterate, Get, Create, Update, Delete |
/api/v1/hosts |
| Blocklists | client.DataSources |
List, Iterate, Get |
/api/v1/data-sources |
| Check profiles | client.MonitoringProfiles |
List, Iterate, Get, Create, Update, Delete |
/api/v1/data-source-groups |
| Alert channels | client.Alerts |
List, Iterate, Get, Create, Update, Delete |
/api/v1/alerts |
| Delivery hours | client.ContactGroups |
List, Iterate, Get, Create, Update, Delete |
/api/v1/alert-groups |
| Blocklist checks | client.Blacklist |
Check, Status, CheckAndWait, WaitFor |
/api/v1/blacklist |
| Certificate checks | client.Certificates |
Check, Status, CheckAndWait, WaitFor |
/api/v1/certificates |
| Email authentication checks | client.Deliverability |
Check, Status, CheckAndWait, WaitFor |
/api/v1/deliverability |
| Prometheus metrics | client.Metrics |
Get |
/api/v1/metrics |
Listreturns one page as a*Page[T]withData,Meta,LinksandHasNext(). SetPageandPerPage(1–100; the API sends 15 when you leave it out) in the resource’s list params.Iteratewalks every page as aniter.Seq2[T, error]forrange. Read Pagination.Get,UpdateandDeletetake theuuid, exceptDataSources.Get, which takes the blocklist’s numericid.UpdatesendsPUTwith the fields you set. Update params are pointers: usehostrepute.String,hostrepute.Intandhostrepute.Boolto fill them.- The SDK has no method for sending a test alert. Call
POST /api/v1/alerts/{alert}/testdirectly.
Add a domain or IP
Section titled “Add a domain or IP”Every domain or IP needs a check profile. The SDK calls it
MonitoringProfileUUID and sends it as data_source_group_uuid:
profiles, err := client.MonitoringProfiles.List(ctx, nil)if err != nil { log.Fatal(err)}var profileUUID stringfor _, p := range profiles.Data { if p.IsDefault { profileUUID = p.UUID }}
host, err := client.Hosts.Create(ctx, hostrepute.HostCreateParams{ Name: "Mail", Host: "mail.example.com", MonitoringProfileUUID: profileUUID,})Set delivery hours and an alert channel
Section titled “Set delivery hours and an alert channel”Delivery hours are ContactGroups in the SDK. Schedule is a
map[string]any that the SDK sends unchanged, so give it the shape the API expects:
- Keys
mon,tue,wed,thu,fri,satandsun, each withenabled,startandend. Times areHH:MM, and an enabled day must end after it starts. - A day you leave out gets no alerts. Leave
Scheduleout entirely for delivery hours that are open at any time. Updateleaves out empty values, so it can’t turn existing delivery hours back to any time. Send"schedule": nullwith the REST API instead.- The SDK’s README shows a
daysandhoursshape: the API rejects it with422.
day := func(enabled bool) map[string]any { return map[string]any{"enabled": enabled, "start": "08:00", "end": "18:00"}}
hours, err := client.ContactGroups.Create(ctx, hostrepute.ContactGroupCreateParams{ Name: "Business hours", Timezone: "America/New_York", Schedule: map[string]any{ "mon": day(true), "tue": day(true), "wed": day(true), "thu": day(true), "fri": day(true), "sat": day(false), "sun": day(false), },})An alert channel is Alerts. Settings holds the field the channel type needs
(email here; Set up alert channels lists them all), and ContactGroupUUIDs the delivery
hours it follows:
channel, err := client.Alerts.Create(ctx, hostrepute.AlertCreateParams{ Type: hostrepute.AlertTypeEmail, Frequency: hostrepute.AlertFrequencyOnceOnListedDelisted, Settings: map[string]any{"email": "ops@example.com"}, ContactGroupUUIDs: []string{hours.UUID},})For Frequency, use AlertFrequencyOnceOnListedDelisted (Listed and removed in
the portal) or AlertFrequencyOncePerCheckWhileListed (Only when listed). The SDK
also defines AlertFrequencyDaily, which the API rejects with 422, and AlertFrequencyEveryCheck, a retired value
that the API stores as once_on_listed_delisted.
Run checks and wait for the result
Section titled “Run checks and wait for the result”Each check uses 1 credit (credit costs). Blocklist and certificate checks run in the background:
Checkstarts the check and returns it withStatuspending.Statusreads it again by UUID.WaitForpollsStatusuntil the check iscompletedorfailed.CheckAndWaitisCheckfollowed byWaitFor.
WaitOptions sets how long to wait (Timeout, 60 seconds by default) and how often to poll (PollInterval,
2 seconds). When the time runs out, the error matches hostrepute.ErrTimeout (test it with hostrepute.IsTimeout) and
the returned scan holds the last status read, so you can resume with WaitFor:
scan, err := client.Blacklist.CheckAndWait(ctx, hostrepute.BlacklistCheckParams{Host: "mail.example.com"}, hostrepute.WaitOptions{Timeout: 2 * time.Minute, PollInterval: 5 * time.Second},)if hostrepute.IsTimeout(err) && scan != nil { log.Printf("scan %s is still running; resume with client.Blacklist.WaitFor", scan.UUID) return}if err != nil { log.Fatal(err)}fmt.Printf("%s: listed on %d of %d blocklists\n", scan.Status, scan.ListedDataSourceCount, scan.DataSourceCount)A failed check comes back as a result, not an error: check Status and ErrorMessage. The full per-blocklist
result is in scan.Result. A certificate check works the same way; Protocol takes a pointer:
protocol := hostrepute.CertificateProtocolStartTLSSMTPcert, err := client.Certificates.CheckAndWait(ctx, hostrepute.CertificateCheckParams{Host: "smtp.example.com", Protocol: &protocol, Port: hostrepute.Int(587)}, hostrepute.WaitOptions{},)To be told when a check ends instead of polling, set CallbackURL on BlacklistCheckParams or
CertificateCheckParams. A callback’s signature can’t be verified yet, so treat the callback as a notification and
read the result with Status, as Receive webhooks explains. The SDK’s own
webhook helpers don’t match what HostRepute sends, so don’t use them.
Run checks and wait for results covers the API side of polling and callbacks.
Email authentication checks
Section titled “Email authentication checks”An email authentication check answers in the same request, so Deliverability.Check already returns the final
result. Its Status is passed, warning or failed, or skipped when none of the checks applied to the host:
result, err := client.Deliverability.Check(ctx, hostrepute.DeliverabilityCheckParams{ Host: "example.com", Checks: []hostrepute.DeliverabilityCheck{ hostrepute.DeliverabilityCheckSPFRecord, hostrepute.DeliverabilityCheckDMARCRecord, },})if err != nil { log.Fatal(err)}fmt.Println(result.Status)Retries
Section titled “Retries”The SDK retries a failed request up to 3 attempts in total:
429is retried for every method. The SDK waits forRetry-After(seconds or an HTTP date) when the response has it. A429means the API refused the request before running it, so a retried check isn’t charged twice.5xxand network errors are retried only forGET,HEAD,OPTIONS,PUTandDELETE. APOSTthat creates something or starts a check isn’t retried, so the SDK never starts a check twice.- Backoff without
Retry-Afteris a random delay between zero and 200 ms × 2attempt − 1, capped at 5 seconds. - When the attempts run out, you get the error for the last response, for example a
*RateLimitError. Cancelling the context stops the wait at once.
client, err := hostrepute.New(token, hostrepute.WithRetry(hostrepute.RetryConfig{ MaxAttempts: 5, BaseDelay: 500 * time.Millisecond, MaxDelay: 10 * time.Second, }),)hostrepute.RetryConfig{MaxAttempts: 1} turns retries off. Rate limits lists the limits
behind 429.
Errors
Section titled “Errors”Every API error is a typed error; use errors.As to tell them apart. Each one embeds *hostrepute.APIError, with
StatusCode, Message, Errors, Body, RawBody and Header.
| Status or cause | Type | Extra fields |
|---|---|---|
401 |
*AuthenticationError |
|
402 |
*PaymentRequiredError |
RequiredCredits, AvailableCredits |
403 |
*AuthorizationError |
|
404 |
*NotFoundError |
|
422 |
*ValidationError |
Errors, a map of field names to messages |
429 |
*RateLimitError |
RetryAfter, a time.Duration |
5xx |
*ServerError |
|
| Any other status | *APIError |
|
| No response | *NetworkError |
Err, the transport error |
| A response the SDK can’t read | *DecodingError |
RawBody |
| A wait helper’s timeout | matches hostrepute.ErrTimeout |
_, err := client.Blacklist.Check(ctx, hostrepute.BlacklistCheckParams{Host: "mail.example.com"})
var credits *hostrepute.PaymentRequiredErrorvar invalid *hostrepute.ValidationErrorvar limited *hostrepute.RateLimitErrorswitch {case errors.As(err, &credits): log.Printf("needs %d credits, %d left", credits.RequiredCredits, credits.AvailableCredits)case errors.As(err, &invalid): for field, messages := range invalid.Errors { log.Println(field, messages) }case errors.As(err, &limited): log.Printf("rate limited, retry in %s", limited.RetryAfter)case err != nil: log.Fatal(err)}Errors shows the response body behind each status.
Prometheus metrics
Section titled “Prometheus metrics”client.Metrics.Get returns the team’s metrics as Prometheus text. The token needs metrics:read.
text, err := client.Metrics.Get(ctx)if err != nil { log.Fatal(err)}fmt.Print(text)Related
Section titled “Related”- Official SDKs compares the five SDKs.
- Make your first API call uses the REST API without an SDK.
- Run checks and wait for results explains polling, callbacks and credits.
- API token abilities lists what each ability allows.
- The API reference documents every operation.

