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
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
Rust library
Check access
Receive webhooks
Persons and events
Custom payment providers

Persons and events

Create and update persons, capture events and send push notifications from Rust.

Rust code for persons, events and push notifications, using a configured client.

Persons

Create a person

use voidhash::generated::types::CreatePersonBodyJsonEncoding;

let person = voidhash
    .persons()
    .create(&CreatePersonBodyJsonEncoding {
        distinct_id: "user_123".parse()?,
        email: Some("ada@example.com".into()),
        name: Some("Ada".into()),
    })
    .await?;

println!("{}", person.id); // person_…

email, name and created_at are Options.

Find a person

get_by_distinct_id fails with a not_found Error::Api for an unknown distinct ID:

match voidhash.persons().get_by_distinct_id("user_123").await {
    Ok(person) => println!("{}", person.id),
    Err(error) if error.is_not_found() => println!("never identified"),
    Err(error) => return Err(error.into()),
}

get fails the same way for an unknown or erased ID.

let person = voidhash.persons().get("person_k2v9x4m8q1r3").await?;

entitlements takes the same ID; list returns only the first page of persons.

Update attributes

set_attributes sets attributes but fails with person_not_found for a new distinct ID, so create the person first.

use serde_json::{json, Map, Value};
use voidhash::PersonAttributes;

let object = |value: Value| -> Map<String, Value> { value.as_object().cloned().unwrap_or_default() };

voidhash
    .persons()
    .set_attributes(&PersonAttributes {
        distinct_id: "user_123".into(),
        traits: Some(object(json!({ "plan": "team", "seats": 5 }))),
        set_once: Some(object(json!({ "signupSource": "website" }))),
        ..PersonAttributes::default()
    })
    .await?;

Capture events

Event::new(event, distinct_id, timestamp) has the setters .property, .properties, .context_property, .context, .uuid and .session_id.

Create the client with ingest_url set to "https://api.voidhash.com"; the default capture host doesn't answer yet.

use voidhash::Event;

voidhash
    .event_capture()
    .capture(
        &Event::new("report_exported", "user_123", chrono::Utc::now())
            .property("format", "csv")
            .property("rows", 1200),
    )
    .await?;

capture_batch sends a slice in one request; an empty slice sends nothing.

use voidhash::Event;

let now = chrono::Utc::now();
let result = voidhash
    .event_capture()
    .capture_batch(&[
        Event::new("trial_reminder_sent", "user_123", now),
        Event::new("trial_reminder_sent", "user_456", now),
    ])
    .await?;

println!("{} accepted, {} rejected", result.accepted, result.rejected);

Errors are an Error::Api whose code is an event capture code.

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.

notifications().send sends no idempotency key, so a retry after a timeout can notify twice.

use serde_json::{json, Map, Value};
use voidhash::generated::types::CreatePushNotificationBodyJsonEncoding;

let data: Map<String, Value> = [("screen".to_owned(), json!("paywall"))].into_iter().collect();

let sent = voidhash
    .notifications()
    .send(&CreatePushNotificationBodyJsonEncoding {
        distinct_ids: Some(vec!["user_123".into()]),
        person_ids: None,
        title: "Your trial ends tomorrow".parse()?,
        body: "Keep Pro for $9.99 a month.".parse()?,
        data: Some(data),
        sound: None,
        badge: None,
        priority: None,
        ttl_seconds: None,
        channel_id: None,
        collapse_id: None,
    })
    .await?;

println!("{} {} {:?}", sent.id, sent.device_count, sent.unresolved_distinct_ids);

priority takes Default or High; see Send a push for the other fields.

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 eventsSend push notificationsNext steps