VoidhashDocs
DevelopersHelp centerGuidesAPI reference
Dashboard
Get started
Introduction
Quickstart
How Voidhash works
Glossary
Versions and releases
Concepts
Teams, projects and environments
API keys
Products and perks
Offers
Subscription lifecycle
People and identity
Groups
Events
Features
Paywalls in your app
Feature flags and A/B tests
Paywall components
Push notifications
Ad attribution in your app
Client SDKs
React Native
Swift
Kotlin
Web
Your backend
Node.js
PHP
Go
Rust
Other languages
Payment sources
Forward store notifications
Developer tools
CLI
MCP server
Query analytics with VoidQL
Go library
Check access
Receive webhooks
Persons and events
Custom payment providers

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

Early access

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

  • Receive webhooks
  • People and identity
  • Events

Something wrong or missing on this page? Tell us by email or on Discord.

PreviousReceive webhooksNextCustom payment providers

On this page

PersonsCreate a personFind a personUpdate attributesCapture eventsGroupsSend push notificationsNext steps