Track an event
curl --request POST \
--url https://galinum.com/api/v1/track \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"userId": "user_123",
"event": "activated_workspace",
"props": {
"workspaceId": "ws_1",
"$pathname": "/onboarding"
},
"eventId": "<string>"
}
'import requests
url = "https://galinum.com/api/v1/track"
payload = {
"userId": "user_123",
"event": "activated_workspace",
"props": {
"workspaceId": "ws_1",
"$pathname": "/onboarding"
},
"eventId": "<string>"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
userId: 'user_123',
event: 'activated_workspace',
props: {workspaceId: 'ws_1', $pathname: '/onboarding'},
eventId: '<string>'
})
};
fetch('https://galinum.com/api/v1/track', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://galinum.com/api/v1/track",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'userId' => 'user_123',
'event' => 'activated_workspace',
'props' => [
'workspaceId' => 'ws_1',
'$pathname' => '/onboarding'
],
'eventId' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://galinum.com/api/v1/track"
payload := strings.NewReader("{\n \"userId\": \"user_123\",\n \"event\": \"activated_workspace\",\n \"props\": {\n \"workspaceId\": \"ws_1\",\n \"$pathname\": \"/onboarding\"\n },\n \"eventId\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://galinum.com/api/v1/track")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"userId\": \"user_123\",\n \"event\": \"activated_workspace\",\n \"props\": {\n \"workspaceId\": \"ws_1\",\n \"$pathname\": \"/onboarding\"\n },\n \"eventId\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://galinum.com/api/v1/track")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"userId\": \"user_123\",\n \"event\": \"activated_workspace\",\n \"props\": {\n \"workspaceId\": \"ws_1\",\n \"$pathname\": \"/onboarding\"\n },\n \"eventId\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"ok": true
}{
"error": "userId is required"
}{
"error": "Unauthorized"
}{
"error": "Invalid request"
}{
"error": "Too many requests"
}{
"error": "Could not identify user"
}SDK endpoints
Track an event
Records a behavioral event for a user — the substrate Galinum’s agents analyze for campaign targeting. Tracking implicitly upserts the user, so it is safe to call for users not yet identified. When the event name matches the targetEvent of a goal linked to a campaign (via goalId), exposed deliveries resolve to converted automatically. Exposure is shownAt for web in-app and deliveredAt for email.
POST
/
api
/
v1
/
track
Track an event
curl --request POST \
--url https://galinum.com/api/v1/track \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"userId": "user_123",
"event": "activated_workspace",
"props": {
"workspaceId": "ws_1",
"$pathname": "/onboarding"
},
"eventId": "<string>"
}
'import requests
url = "https://galinum.com/api/v1/track"
payload = {
"userId": "user_123",
"event": "activated_workspace",
"props": {
"workspaceId": "ws_1",
"$pathname": "/onboarding"
},
"eventId": "<string>"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
userId: 'user_123',
event: 'activated_workspace',
props: {workspaceId: 'ws_1', $pathname: '/onboarding'},
eventId: '<string>'
})
};
fetch('https://galinum.com/api/v1/track', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://galinum.com/api/v1/track",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'userId' => 'user_123',
'event' => 'activated_workspace',
'props' => [
'workspaceId' => 'ws_1',
'$pathname' => '/onboarding'
],
'eventId' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://galinum.com/api/v1/track"
payload := strings.NewReader("{\n \"userId\": \"user_123\",\n \"event\": \"activated_workspace\",\n \"props\": {\n \"workspaceId\": \"ws_1\",\n \"$pathname\": \"/onboarding\"\n },\n \"eventId\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://galinum.com/api/v1/track")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"userId\": \"user_123\",\n \"event\": \"activated_workspace\",\n \"props\": {\n \"workspaceId\": \"ws_1\",\n \"$pathname\": \"/onboarding\"\n },\n \"eventId\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://galinum.com/api/v1/track")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"userId\": \"user_123\",\n \"event\": \"activated_workspace\",\n \"props\": {\n \"workspaceId\": \"ws_1\",\n \"$pathname\": \"/onboarding\"\n },\n \"eventId\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"ok": true
}{
"error": "userId is required"
}{
"error": "Unauthorized"
}{
"error": "Invalid request"
}{
"error": "Too many requests"
}{
"error": "Could not identify user"
}Authorizations
Your project's publishable key (pk_pub_…). Safe to expose in the browser — it identifies the project and is rate-limited, not secret.
Body
application/json
Maximum string length:
256Example:
"user_123"
Event name. Use stable, snake_case names.
Maximum string length:
80Example:
"activated_workspace"
Optional event properties (max 4 KB serialized). The browser SDK adds $current_url and $pathname automatically.
Example:
{
"workspaceId": "ws_1",
"$pathname": "/onboarding"
}
Required string length:
1 - 128Response
Success.