Persons and events
Create and update persons, capture events, describe groups and send push notifications from Go.
Go code for persons, events and push notifications, using a configured client.
Persons
Create a person
email, name := "ada@example.com", "Ada"
person, err := client.Persons.Create(ctx, voidhash.CreatePersonParams{
DistinctId: "user_123",
Email: &email,
Name: &name,
})
if err != nil {
return err
}
fmt.Println(person.Id) // person_…Email, Name and CreatedAt are pointers that can be nil.
Find a person
GetByDistinctID fails with a 404 *APIError for an unknown distinct ID:
person, err := client.Persons.GetByDistinctID(ctx, "user_123")
switch {
case voidhash.IsNotFound(err):
fmt.Println("never identified")
case err != nil:
return err
default:
fmt.Println(person.Id)
}Get fails the same way for an unknown or erased ID.
person, err := client.Persons.Get(ctx, "person_k2v9x4m8q1r3")List returns every person in the project, newest first.
Update attributes
SetAttributes sets attributes and creates the person
when the distinct ID is new.
_, err := client.Persons.SetAttributes(ctx, voidhash.SetPersonAttributesParams{
DistinctID: "user_123",
Traits: map[string]any{"plan": "team", "seats": 5},
SetOnce: map[string]any{"signupSource": "website"},
})Capture events
EventCapture.Capture returns an error before any request for a zero Timestamp.
Create the client with voidhash.WithIngestURL("https://api.voidhash.com"); the default capture
host doesn't answer yet.
_, err := client.EventCapture.Capture(ctx, voidhash.Event{
DistinctID: "user_123",
Event: "report_exported",
Timestamp: time.Now(),
Properties: map[string]any{"format": "csv", "rows": 1200},
})EventCapture.CaptureBatch sends a slice in one request; an empty slice sends nothing.
now := time.Now()
result, err := client.EventCapture.CaptureBatch(ctx, []voidhash.Event{
{DistinctID: "user_123", Event: "trial_reminder_sent", Timestamp: now},
{DistinctID: "user_456", Event: "trial_reminder_sent", Timestamp: now},
})
if err == nil {
fmt.Println(result.Accepted, result.Rejected)
}Errors are an *APIError whose Code is an
event capture code.
Groups
Groups are what your users belong to, such as their company. Name an event's
groups with Groups, by group type; they are sent as its $groups property:
_, err := client.EventCapture.Capture(ctx, voidhash.Event{
DistinctID: "user_123",
Event: "report_exported",
Timestamp: time.Now(),
Groups: map[string]string{"company": "acme"},
})EventCapture.GroupIdentify sets a group's properties, such as what your backend knows of a
company's plan and seats. SetOnce fills only properties the group has no value for, and a later
change of a property wins. A zero Timestamp means now.
_, err := client.EventCapture.GroupIdentify(ctx, voidhash.GroupIdentify{
GroupType: "company",
GroupKey: "acme",
Properties: map[string]any{"name": "Acme", "plan": "pro", "seats": 40},
SetOnce: map[string]any{"first_plan": "trial"},
})The $groupidentify event it sends belongs to no person.
Send push notifications
Push notifications are in early access. Ask us on Discord, or email support@voidhash.com on a paid plan, to turn them on for your team.
A retry of SendWithIdempotencyKey with the same key returns the first send; Send takes no key.
data := map[string]any{"screen": "paywall"}
sent, err := client.Notifications.SendWithIdempotencyKey(ctx, voidhash.Notification{
DistinctIds: &[]string{"user_123"},
Title: "Your trial ends tomorrow",
Body: "Keep Pro for $9.99 a month.",
Data: &data,
}, "renewal-reminder-user_123-2026-11")
if err != nil {
return err
}
fmt.Println(sent.Id, sent.DeviceCount, sent.UnresolvedDistinctIds)The optional fields are Sound, Badge, Priority, TtlSeconds, ChannelId and CollapseId;
see Send a push.
Next steps
Something wrong or missing on this page? Tell us by email or on Discord.