SDK Docs

Track 5 events. Voltaire handles the rest.

Quickstart

After signing up, connect your Stripe or RevenueCat account, then add 5 tracking calls to your app. Voltaire's Claude Code plugin installs the SDK automatically — just run:

Claude Code
/voltaire

Voltaire detects your platform, writes the helper, and instruments the 5 events. You can also do it manually — see the platform sections below.

Events reference

Track exactly these 5 events — no more, no less.

EventWhen to fire
session_started App launch or user login — needed to compute session-to-conversion rates
feature_used When the user hits the key feature that leads to the paywall — identifies your value moment
paywall_shown When the paywall UI becomes visible
paywall_dismissed When the user closes the paywall without purchasing — include dismiss_seconds
paywall_converted After a successful purchase or subscription

JavaScript / TypeScript

No npm package needed — plain fetch. Store your API key in an env variable.

typescript
const VOLTAIRE_KEY = process.env.VOLTAIRE_API_KEY
const VOLTAIRE_URL = 'https://api.hivoltaire.com/api/events'

async function voltaireEvent(type: string, userId: string, extra?: Record) {
  await fetch(VOLTAIRE_URL, {
    method: 'POST',
    headers: { 'X-Api-Key': VOLTAIRE_KEY, 'Content-Type': 'application/json' },
    body: JSON.stringify({ event_type: type, user_session_id: userId, ...extra }),
  }).catch(() => {}) // fire-and-forget, never block the UI
}

// 1. New session
voltaireEvent('session_started', userId)

// 2. Key feature used
voltaireEvent('feature_used', userId)

// 3. Paywall appears — save the timestamp
const paywallShownAt = Date.now()
voltaireEvent('paywall_shown', userId)

// 4a. User closes without buying
voltaireEvent('paywall_dismissed', userId, { dismiss_seconds: (Date.now() - paywallShownAt) / 1000 })

// 4b. User subscribes
voltaireEvent('paywall_converted', userId)

iOS (Swift)

No SDK to install — uses URLSession which is built into iOS.

swift
// VoltaireTracker.swift — add this file to your project
func voltaireEvent(_ type: String, userId: String, extra: [String: Any] = [:]) {
    guard let url = URL(string: "https://api.hivoltaire.com/api/events") else { return }
    var req = URLRequest(url: url)
    req.httpMethod = "POST"
    req.setValue(ProcessInfo.processInfo.environment["VOLTAIRE_API_KEY"], forHTTPHeaderField: "X-Api-Key")
    req.setValue("application/json", forHTTPHeaderField: "Content-Type")
    var body: [String: Any] = ["event_type": type, "user_session_id": userId]
    body.merge(extra) { _, new in new }
    req.httpBody = try? JSONSerialization.data(withJSONObject: body)
    URLSession.shared.dataTask(with: req).resume()
}

// 1. App launch
voltaireEvent("session_started", userId: currentUser.id)

// 2. Key feature used
voltaireEvent("feature_used", userId: currentUser.id)

// 3. Paywall appears
var paywallShownAt = Date()
voltaireEvent("paywall_shown", userId: currentUser.id)

// 4a. User closes without buying
voltaireEvent("paywall_dismissed", userId: currentUser.id,
    extra: ["dismiss_seconds": Date().timeIntervalSince(paywallShownAt)])

// 4b. After purchase
voltaireEvent("paywall_converted", userId: currentUser.id)

Store your API key in Info.plist or an xcconfig file — never hardcode it.

Android (Kotlin)

No SDK to install — uses OkHttp, which is already in most Android projects.

kotlin
// build.gradle.kts (app) — OkHttp is likely already present
dependencies {
    implementation("com.squareup.okhttp3:okhttp:4.12.0")
}
kotlin
// VoltaireTracker.kt
import okhttp3.*
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.RequestBody.Companion.toRequestBody
import org.json.JSONObject

fun voltaireEvent(type: String, userId: String, extra: Map = emptyMap()) {
    val body = JSONObject(mapOf("event_type" to type, "user_session_id" to userId) + extra)
        .toString().toRequestBody("application/json".toMediaType())
    val request = Request.Builder()
        .url("https://api.hivoltaire.com/api/events")
        .addHeader("X-Api-Key", BuildConfig.VOLTAIRE_API_KEY)
        .post(body).build()
    Thread { OkHttpClient().newCall(request).execute().close() }.start()
}

// 1. App launch
voltaireEvent("session_started", currentUser.id)

// 2. Key feature used
voltaireEvent("feature_used", currentUser.id)

// 3. Paywall appears
val paywallShownAt = System.currentTimeMillis()
voltaireEvent("paywall_shown", currentUser.id)

// 4a. User closes without buying
voltaireEvent("paywall_dismissed", currentUser.id,
    mapOf("dismiss_seconds" to (System.currentTimeMillis() - paywallShownAt) / 1000.0))

// 4b. After purchase
voltaireEvent("paywall_converted", currentUser.id)

Store your API key in local.properties and expose via BuildConfig.

Request format

All events go to the same endpoint via HTTP POST.

http
POST https://api.hivoltaire.com/api/events
X-Api-Key: volt_YOUR_API_KEY
Content-Type: application/json

{
  "event_type": "paywall_shown",   // required — one of the 5 events above
  "user_session_id": "user_abc"    // required — your user or device ID
}

Returns {"ok": true, "event_id": "..."} on success. Fire-and-forget — don't block your UI on it.

Optional fields

FieldTypeWhen to use
dismiss_seconds number On paywall_dismissed — time user spent on the paywall
feature string On feature_used — name of the feature (e.g. "export_pdf")

Claude Code plugin

The plugin installs the SDK, instruments the 5 events, and applies your weekly recommendation — all from the terminal. Install it once:

Claude Code
/plugin install voltaire@voltairehq

A browser window opens to connect your account. No API key to copy. Then run from any project:

Claude Code
/voltaire

Requires Claude Code.