Go library
A context-aware server-side client for the Voidhash API.
github.com/voidhashcom/voidhash-go is a context-aware client for Go backends. It needs a
secret key, so run it on your server only.
Install
github.com/voidhashcom/voidhash-go installs from a clone of the
Voidhash repository, through a replace directive:
git clone https://github.com/voidhashcom/voidhash.git third_party/voidhashgo mod edit -replace github.com/voidhashcom/voidhash-go=./third_party/voidhash/libraries/go
go get github.com/voidhashcom/voidhash-goTo pin a build, check out a commit in the clone (git -C third_party/voidhash checkout <commit>), or
add the repository as a Git submodule so your repository records the commit.
The library is an alpha release and isn't on the Go module proxy yet. Pin a commit and update regularly. See Versions and releases.
Requirements: Go 1.22 or later. The client sends requests with net/http.
Create a client
Create one client with your secret key and share it across your server. It is safe for concurrent use.
package main
import (
"log"
"os"
voidhash "github.com/voidhashcom/voidhash-go"
)
func main() {
client, err := voidhash.New(
os.Getenv("VOIDHASH_SECRET_KEY"),
// Event capture is served from the API host for now.
voidhash.WithIngestURL("https://api.voidhash.com"),
)
if err != nil {
log.Fatalf("create voidhash client: %v", err)
}
_ = client // pass it to your handlers
}New takes the secret key and these options:
| Option | Default | Description |
|---|---|---|
WithProjectID(id) | The key's project | Skips the project lookup. Concurrent first calls share one lookup. |
WithBaseURL(url) | https://api.voidhash.com | The API origin. |
WithIngestURL(url) | https://ingest.voidhash.com | The event capture origin. Use https://api.voidhash.com; the default host doesn't answer yet. |
WithPublishableKey(key) | — | Sent as the body token on event capture. Optional. |
WithHTTPClient(client) | A client with no timeout | An *http.Client for timeouts, proxies or tracing. |
WithHeader(name, value) | — | An extra header for every request. Repeat it for more. |
New makes no request. It returns an error when the secret key is empty or a header sets
Authorization or x-secret-key.
Call the API
Each resource is a service field on the client, such as client.Persons or client.Webhooks.
Every method takes a context.Context first, then IDs and a params struct. Request and response
types mirror the API reference; optional fields are pointers. List methods follow
every page and return a slice.
perks, err := client.Perks.List(ctx)
if err != nil {
return err
}
for _, perk := range perks {
fmt.Println(perk.Slug)
}
email := "ada@example.com"
person, err := client.Persons.Create(ctx, voidhash.CreatePersonParams{
DistinctId: "user_123",
Email: &email,
})| Field | Covers |
|---|---|
Persons | Persons, attributes and access checks. |
Perks, Products | The catalog, and the perks each product grants. |
Paywalls | Paywall locations. |
Webhooks | Webhook endpoints and deliveries. |
EventCapture | Events. |
Notifications | Push notifications. |
PaymentSources | Payment sources. |
APIKeys, Schema | The project's API keys and runtime schema. |
For an endpoint without a method here, call the REST API directly.
Handle errors
A failed API call returns a *voidhash.APIError holding the API error.
Read it with errors.As and branch on Type and Code:
person, err := client.Persons.Get(ctx, "person_k2v9x4m8q1r3")
var apiErr *voidhash.APIError
switch {
case err == nil:
return person, nil
case errors.As(err, &apiErr) && apiErr.Type == "not_found":
return nil, nil
case errors.As(err, &apiErr) && (apiErr.Type == "unauthenticated" || apiErr.Type == "permission_denied"):
return nil, fmt.Errorf("the Voidhash secret key is invalid or lacks access: %w", err)
default:
return nil, err
}It also carries Param, the HTTP StatusCode and the RequestID.
voidhash.IsNotFound(err) and voidhash.StatusCode(err) work through wrapped errors. A client
misconfiguration is an *APIError with status 400 and no Type. Network failures and context
cancellation are returned as the underlying error, not an *APIError. The library doesn't retry
or cache.
Timeouts and cancellation
Every call stops when its context ends, so pass the request's context and give it a deadline:
ctx, cancel := context.WithTimeout(r.Context(), 5*time.Second)
defer cancel()
perks, err := client.Perks.List(ctx)For a client-wide limit, pass voidhash.WithHTTPClient(&http.Client{Timeout: 10 * time.Second}).
Next steps
Something wrong or missing on this page? Tell us by email or on Discord.