Analytics
Product analytics: track, identify, funnels and cohorts.
1. Overview
https://api.infrai.cc/v1/analyticsAuthorization: Bearer $INFRAI_API_KEY# Call any /v1/analytics capability over raw HTTP — no SDK to install.
# curl:
curl https://api.infrai.cc/v1/analytics/... \
-H "Authorization: Bearer $INFRAI_API_KEY" \
-H "Content-Type: application/json"2. Methods (8)
2.1analytics.track
Track one or more analytics events.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
event | string | Required | Event name.pattern: ^[a-zA-Z][a-zA-Z0-9_.-]{0,127}$ |
distinct_id | string | Required | Stable id of the acting user. |
properties | Record<string, unknown> | Optional | Arbitrary event properties. |
Returns
{ ok, accepted }| Name | Type | Description |
|---|---|---|
accepted | boolean | Number of items accepted for processing |
event_id | string | null | Unique identifier for this event |
reason | string | null | Reason for the current state or action |
Example
一次性前置(每个范例都假定已完成):
# No SDK to install — every call is a plain HTTPS request.
# Get a project key by signing in at https://infrai.cc/login (Google/GitHub gives
# you $2 free credit; email sign-in starts at $0). On 402 INSUFFICIENT_CREDIT, add
# funds at https://infrai.cc/billing (or POST /v1/account/topup and open the
# returned checkout_url).
export INFRAI_API_KEY="ifr_..."curl -X POST https://api.infrai.cc/v1/analytics/track \
-H "Authorization: Bearer $INFRAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{"event": "sample", "distinct_id": "sample"}'# Zero-install REST call — no SDK required (short-term the API is REST-only).
import os, requests
resp = requests.post(
"https://api.infrai.cc/v1/analytics/track",
headers={
"Authorization": f"Bearer {os.environ['INFRAI_API_KEY']}",
},
json={'event': 'sample', 'distinct_id': 'sample'},
)
resp.raise_for_status()
print(resp.json())// Zero-install REST call — no SDK required (short-term the API is REST-only).
const resp = await fetch(
"https://api.infrai.cc/v1/analytics/track",
{
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.INFRAI_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({"event": "sample", "distinct_id": "sample"}),
},
);
console.log(await resp.json());// Zero-install REST call — no SDK required (short-term the API is REST-only).
const resp = await fetch(
"https://api.infrai.cc/v1/analytics/track",
{
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.INFRAI_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({"event": "sample", "distinct_id": "sample"}),
},
);
if (!resp.ok) throw new Error(`infrai ${resp.status}`);
const data: unknown = await resp.json();
console.log(data);// Zero-install REST call — no SDK required (short-term the API is REST-only).
package main
import (
"bytes"
"fmt"
"net/http"
"os"
)
func main() {
body := []byte(`{"event": "sample", "distinct_id": "sample"}`)
req, _ := http.NewRequest("POST", "https://api.infrai.cc/v1/analytics/track", bytes.NewReader(body))
req.Header.Set("Authorization", "Bearer "+os.Getenv("INFRAI_API_KEY"))
req.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
fmt.Println(resp.Status)
}// Zero-install REST call — no SDK required (short-term the API is REST-only).
import java.net.URI;
import java.net.http.*;
HttpRequest req = HttpRequest.newBuilder()
.uri(URI.create("https://api.infrai.cc/v1/analytics/track"))
.header("Authorization", "Bearer " + System.getenv("INFRAI_API_KEY"))
.header("Content-Type", "application/json")
.method("POST", HttpRequest.BodyPublishers.ofString("{\"event\": \"sample\", \"distinct_id\": \"sample\"}"))
.build();
HttpResponse<String> resp = HttpClient.newHttpClient()
.send(req, HttpResponse.BodyHandlers.ofString());
System.out.println(resp.body());// Zero-install REST call — no SDK required (short-term the API is REST-only).
using System;
using System.Net.Http;
var client = new HttpClient();
var req = new HttpRequestMessage(new HttpMethod("POST"), "https://api.infrai.cc/v1/analytics/track");
var key = Environment.GetEnvironmentVariable("INFRAI_API_KEY");
req.Headers.Add("Authorization", "Bearer " + key);
req.Content = new StringContent("{\"event\": \"sample\", \"distinct_id\": \"sample\"}", System.Text.Encoding.UTF8, "application/json");
var resp = await client.SendAsync(req);
Console.WriteLine(await resp.Content.ReadAsStringAsync());<?php
// Zero-install REST call — no SDK required (short-term the API is REST-only).
$ch = curl_init("https://api.infrai.cc/v1/analytics/track");
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
"Authorization: Bearer " . getenv("INFRAI_API_KEY"),
"Content-Type: application/json",
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, "{\"event\": \"sample\", \"distinct_id\": \"sample\"}");
$response = curl_exec($ch);
curl_close($ch);
echo $response;# Zero-install REST call — no SDK required (short-term the API is REST-only).
require "net/http"
require "uri"
uri = URI("https://api.infrai.cc/v1/analytics/track")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
req = Net::HTTP::Post.new(uri)
req["Authorization"] = "Bearer #{ENV['INFRAI_API_KEY']}"
req["Content-Type"] = "application/json"
req.body = '{"event": "sample", "distinct_id": "sample"}'
res = http.request(req)
puts res.body// Zero-install REST call — no SDK required (short-term the API is REST-only). (uses the reqwest + tokio crates)
use std::env;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let resp = reqwest::Client::new()
.post("https://api.infrai.cc/v1/analytics/track")
.header("Authorization", format!("Bearer {}", env::var("INFRAI_API_KEY")?))
.header("Content-Type", "application/json")
.body(r#"{"event": "sample", "distinct_id": "sample"}"#)
.send()
.await?;
println!("{}", resp.text().await?);
Ok(())
}2.2analytics.identify
Associate traits with a distinct id.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
distinct_id | string | Required | Stable id of the acting user. |
user_id | string | Optional | Id of the connecting user. |
traits | Record<string, unknown> | Optional | User traits to set. |
Returns
{ ok: boolean }| Name | Type | Description |
|---|---|---|
distinct_id | string | Distinct identifier for the user or entity |
traits_merged_count | integer | null | Number of traits merged during identification≥ 0 |
Example
一次性前置(每个范例都假定已完成):
# No SDK to install — every call is a plain HTTPS request.
# Get a project key by signing in at https://infrai.cc/login (Google/GitHub gives
# you $2 free credit; email sign-in starts at $0). On 402 INSUFFICIENT_CREDIT, add
# funds at https://infrai.cc/billing (or POST /v1/account/topup and open the
# returned checkout_url).
export INFRAI_API_KEY="ifr_..."curl -X POST https://api.infrai.cc/v1/analytics/identify \
-H "Authorization: Bearer $INFRAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{"distinct_id": "sample"}'# Zero-install REST call — no SDK required (short-term the API is REST-only).
import os, requests
resp = requests.post(
"https://api.infrai.cc/v1/analytics/identify",
headers={
"Authorization": f"Bearer {os.environ['INFRAI_API_KEY']}",
},
json={'distinct_id': 'sample'},
)
resp.raise_for_status()
print(resp.json())// Zero-install REST call — no SDK required (short-term the API is REST-only).
const resp = await fetch(
"https://api.infrai.cc/v1/analytics/identify",
{
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.INFRAI_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({"distinct_id": "sample"}),
},
);
console.log(await resp.json());// Zero-install REST call — no SDK required (short-term the API is REST-only).
const resp = await fetch(
"https://api.infrai.cc/v1/analytics/identify",
{
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.INFRAI_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({"distinct_id": "sample"}),
},
);
if (!resp.ok) throw new Error(`infrai ${resp.status}`);
const data: unknown = await resp.json();
console.log(data);// Zero-install REST call — no SDK required (short-term the API is REST-only).
package main
import (
"bytes"
"fmt"
"net/http"
"os"
)
func main() {
body := []byte(`{"distinct_id": "sample"}`)
req, _ := http.NewRequest("POST", "https://api.infrai.cc/v1/analytics/identify", bytes.NewReader(body))
req.Header.Set("Authorization", "Bearer "+os.Getenv("INFRAI_API_KEY"))
req.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
fmt.Println(resp.Status)
}// Zero-install REST call — no SDK required (short-term the API is REST-only).
import java.net.URI;
import java.net.http.*;
HttpRequest req = HttpRequest.newBuilder()
.uri(URI.create("https://api.infrai.cc/v1/analytics/identify"))
.header("Authorization", "Bearer " + System.getenv("INFRAI_API_KEY"))
.header("Content-Type", "application/json")
.method("POST", HttpRequest.BodyPublishers.ofString("{\"distinct_id\": \"sample\"}"))
.build();
HttpResponse<String> resp = HttpClient.newHttpClient()
.send(req, HttpResponse.BodyHandlers.ofString());
System.out.println(resp.body());// Zero-install REST call — no SDK required (short-term the API is REST-only).
using System;
using System.Net.Http;
var client = new HttpClient();
var req = new HttpRequestMessage(new HttpMethod("POST"), "https://api.infrai.cc/v1/analytics/identify");
var key = Environment.GetEnvironmentVariable("INFRAI_API_KEY");
req.Headers.Add("Authorization", "Bearer " + key);
req.Content = new StringContent("{\"distinct_id\": \"sample\"}", System.Text.Encoding.UTF8, "application/json");
var resp = await client.SendAsync(req);
Console.WriteLine(await resp.Content.ReadAsStringAsync());<?php
// Zero-install REST call — no SDK required (short-term the API is REST-only).
$ch = curl_init("https://api.infrai.cc/v1/analytics/identify");
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
"Authorization: Bearer " . getenv("INFRAI_API_KEY"),
"Content-Type: application/json",
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, "{\"distinct_id\": \"sample\"}");
$response = curl_exec($ch);
curl_close($ch);
echo $response;# Zero-install REST call — no SDK required (short-term the API is REST-only).
require "net/http"
require "uri"
uri = URI("https://api.infrai.cc/v1/analytics/identify")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
req = Net::HTTP::Post.new(uri)
req["Authorization"] = "Bearer #{ENV['INFRAI_API_KEY']}"
req["Content-Type"] = "application/json"
req.body = '{"distinct_id": "sample"}'
res = http.request(req)
puts res.body// Zero-install REST call — no SDK required (short-term the API is REST-only). (uses the reqwest + tokio crates)
use std::env;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let resp = reqwest::Client::new()
.post("https://api.infrai.cc/v1/analytics/identify")
.header("Authorization", format!("Bearer {}", env::var("INFRAI_API_KEY")?))
.header("Content-Type", "application/json")
.body(r#"{"distinct_id": "sample"}"#)
.send()
.await?;
println!("{}", resp.text().await?);
Ok(())
}2.3analytics.alias
合并身份别名
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
old_id | string | Required | 要合并的来源 distinct_id(例如匿名 id)。 |
new_id | string | Required | 合并目标的规范 distinct_id。 |
idempotency_key | string | Optional | 可选幂等键,确保重复请求只生效一次。 |
Returns
AliasResult { merged: boolean }| Name | Type | Description |
|---|---|---|
old_id | string | Previous identifier before aliasing |
new_id | string | New identifier after aliasing |
merged | boolean | Whether the identities were merged |
Example
一次性前置(每个范例都假定已完成):
# No SDK to install — every call is a plain HTTPS request.
# Get a project key by signing in at https://infrai.cc/login (Google/GitHub gives
# you $2 free credit; email sign-in starts at $0). On 402 INSUFFICIENT_CREDIT, add
# funds at https://infrai.cc/billing (or POST /v1/account/topup and open the
# returned checkout_url).
export INFRAI_API_KEY="ifr_..."curl -X POST https://api.infrai.cc/v1/analytics/alias \
-H "Authorization: Bearer $INFRAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{"old_id": "sample", "new_id": "sample"}'# Zero-install REST call — no SDK required (short-term the API is REST-only).
import os, requests
resp = requests.post(
"https://api.infrai.cc/v1/analytics/alias",
headers={
"Authorization": f"Bearer {os.environ['INFRAI_API_KEY']}",
},
json={'old_id': 'sample', 'new_id': 'sample'},
)
resp.raise_for_status()
print(resp.json())// Zero-install REST call — no SDK required (short-term the API is REST-only).
const resp = await fetch(
"https://api.infrai.cc/v1/analytics/alias",
{
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.INFRAI_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({"old_id": "sample", "new_id": "sample"}),
},
);
console.log(await resp.json());// Zero-install REST call — no SDK required (short-term the API is REST-only).
const resp = await fetch(
"https://api.infrai.cc/v1/analytics/alias",
{
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.INFRAI_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({"old_id": "sample", "new_id": "sample"}),
},
);
if (!resp.ok) throw new Error(`infrai ${resp.status}`);
const data: unknown = await resp.json();
console.log(data);// Zero-install REST call — no SDK required (short-term the API is REST-only).
package main
import (
"bytes"
"fmt"
"net/http"
"os"
)
func main() {
body := []byte(`{"old_id": "sample", "new_id": "sample"}`)
req, _ := http.NewRequest("POST", "https://api.infrai.cc/v1/analytics/alias", bytes.NewReader(body))
req.Header.Set("Authorization", "Bearer "+os.Getenv("INFRAI_API_KEY"))
req.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
fmt.Println(resp.Status)
}// Zero-install REST call — no SDK required (short-term the API is REST-only).
import java.net.URI;
import java.net.http.*;
HttpRequest req = HttpRequest.newBuilder()
.uri(URI.create("https://api.infrai.cc/v1/analytics/alias"))
.header("Authorization", "Bearer " + System.getenv("INFRAI_API_KEY"))
.header("Content-Type", "application/json")
.method("POST", HttpRequest.BodyPublishers.ofString("{\"old_id\": \"sample\", \"new_id\": \"sample\"}"))
.build();
HttpResponse<String> resp = HttpClient.newHttpClient()
.send(req, HttpResponse.BodyHandlers.ofString());
System.out.println(resp.body());// Zero-install REST call — no SDK required (short-term the API is REST-only).
using System;
using System.Net.Http;
var client = new HttpClient();
var req = new HttpRequestMessage(new HttpMethod("POST"), "https://api.infrai.cc/v1/analytics/alias");
var key = Environment.GetEnvironmentVariable("INFRAI_API_KEY");
req.Headers.Add("Authorization", "Bearer " + key);
req.Content = new StringContent("{\"old_id\": \"sample\", \"new_id\": \"sample\"}", System.Text.Encoding.UTF8, "application/json");
var resp = await client.SendAsync(req);
Console.WriteLine(await resp.Content.ReadAsStringAsync());<?php
// Zero-install REST call — no SDK required (short-term the API is REST-only).
$ch = curl_init("https://api.infrai.cc/v1/analytics/alias");
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
"Authorization: Bearer " . getenv("INFRAI_API_KEY"),
"Content-Type: application/json",
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, "{\"old_id\": \"sample\", \"new_id\": \"sample\"}");
$response = curl_exec($ch);
curl_close($ch);
echo $response;# Zero-install REST call — no SDK required (short-term the API is REST-only).
require "net/http"
require "uri"
uri = URI("https://api.infrai.cc/v1/analytics/alias")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
req = Net::HTTP::Post.new(uri)
req["Authorization"] = "Bearer #{ENV['INFRAI_API_KEY']}"
req["Content-Type"] = "application/json"
req.body = '{"old_id": "sample", "new_id": "sample"}'
res = http.request(req)
puts res.body// Zero-install REST call — no SDK required (short-term the API is REST-only). (uses the reqwest + tokio crates)
use std::env;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let resp = reqwest::Client::new()
.post("https://api.infrai.cc/v1/analytics/alias")
.header("Authorization", format!("Bearer {}", env::var("INFRAI_API_KEY")?))
.header("Content-Type", "application/json")
.body(r#"{"old_id": "sample", "new_id": "sample"}"#)
.send()
.await?;
println!("{}", resp.text().await?);
Ok(())
}2.4analytics.batch
批量上报事件
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
events | TrackEvent[] | Required | 至多 1000 条 TrackEvent 事件,每条事件自带幂等键。1–1000 items |
Returns
{ ok: boolean, accepted: number }| Name | Type | Description |
|---|---|---|
accepted | integer | Number of items accepted for processing≥ 0 |
rejected | integer | Number of items rejected due to validation errors≥ 0 |
errors | object[] | Array of per-item errors (for batch operations) |
errors[].index | integer | -≥ 0 |
errors[].reason | string | - |
Example
一次性前置(每个范例都假定已完成):
# No SDK to install — every call is a plain HTTPS request.
# Get a project key by signing in at https://infrai.cc/login (Google/GitHub gives
# you $2 free credit; email sign-in starts at $0). On 402 INSUFFICIENT_CREDIT, add
# funds at https://infrai.cc/billing (or POST /v1/account/topup and open the
# returned checkout_url).
export INFRAI_API_KEY="ifr_..."curl -X POST https://api.infrai.cc/v1/analytics/batch \
-H "Authorization: Bearer $INFRAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{"events": [{"event": "sample", "distinct_id": "sample"}]}'# Zero-install REST call — no SDK required (short-term the API is REST-only).
import os, requests
resp = requests.post(
"https://api.infrai.cc/v1/analytics/batch",
headers={
"Authorization": f"Bearer {os.environ['INFRAI_API_KEY']}",
},
json={'events': [{'event': 'sample', 'distinct_id': 'sample'}]},
)
resp.raise_for_status()
print(resp.json())// Zero-install REST call — no SDK required (short-term the API is REST-only).
const resp = await fetch(
"https://api.infrai.cc/v1/analytics/batch",
{
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.INFRAI_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({"events": [{"event": "sample", "distinct_id": "sample"}]}),
},
);
console.log(await resp.json());// Zero-install REST call — no SDK required (short-term the API is REST-only).
const resp = await fetch(
"https://api.infrai.cc/v1/analytics/batch",
{
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.INFRAI_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({"events": [{"event": "sample", "distinct_id": "sample"}]}),
},
);
if (!resp.ok) throw new Error(`infrai ${resp.status}`);
const data: unknown = await resp.json();
console.log(data);// Zero-install REST call — no SDK required (short-term the API is REST-only).
package main
import (
"bytes"
"fmt"
"net/http"
"os"
)
func main() {
body := []byte(`{"events": [{"event": "sample", "distinct_id": "sample"}]}`)
req, _ := http.NewRequest("POST", "https://api.infrai.cc/v1/analytics/batch", bytes.NewReader(body))
req.Header.Set("Authorization", "Bearer "+os.Getenv("INFRAI_API_KEY"))
req.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
fmt.Println(resp.Status)
}// Zero-install REST call — no SDK required (short-term the API is REST-only).
import java.net.URI;
import java.net.http.*;
HttpRequest req = HttpRequest.newBuilder()
.uri(URI.create("https://api.infrai.cc/v1/analytics/batch"))
.header("Authorization", "Bearer " + System.getenv("INFRAI_API_KEY"))
.header("Content-Type", "application/json")
.method("POST", HttpRequest.BodyPublishers.ofString("{\"events\": [{\"event\": \"sample\", \"distinct_id\": \"sample\"}]}"))
.build();
HttpResponse<String> resp = HttpClient.newHttpClient()
.send(req, HttpResponse.BodyHandlers.ofString());
System.out.println(resp.body());// Zero-install REST call — no SDK required (short-term the API is REST-only).
using System;
using System.Net.Http;
var client = new HttpClient();
var req = new HttpRequestMessage(new HttpMethod("POST"), "https://api.infrai.cc/v1/analytics/batch");
var key = Environment.GetEnvironmentVariable("INFRAI_API_KEY");
req.Headers.Add("Authorization", "Bearer " + key);
req.Content = new StringContent("{\"events\": [{\"event\": \"sample\", \"distinct_id\": \"sample\"}]}", System.Text.Encoding.UTF8, "application/json");
var resp = await client.SendAsync(req);
Console.WriteLine(await resp.Content.ReadAsStringAsync());<?php
// Zero-install REST call — no SDK required (short-term the API is REST-only).
$ch = curl_init("https://api.infrai.cc/v1/analytics/batch");
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
"Authorization: Bearer " . getenv("INFRAI_API_KEY"),
"Content-Type: application/json",
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, "{\"events\": [{\"event\": \"sample\", \"distinct_id\": \"sample\"}]}");
$response = curl_exec($ch);
curl_close($ch);
echo $response;# Zero-install REST call — no SDK required (short-term the API is REST-only).
require "net/http"
require "uri"
uri = URI("https://api.infrai.cc/v1/analytics/batch")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
req = Net::HTTP::Post.new(uri)
req["Authorization"] = "Bearer #{ENV['INFRAI_API_KEY']}"
req["Content-Type"] = "application/json"
req.body = '{"events": [{"event": "sample", "distinct_id": "sample"}]}'
res = http.request(req)
puts res.body// Zero-install REST call — no SDK required (short-term the API is REST-only). (uses the reqwest + tokio crates)
use std::env;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let resp = reqwest::Client::new()
.post("https://api.infrai.cc/v1/analytics/batch")
.header("Authorization", format!("Bearer {}", env::var("INFRAI_API_KEY")?))
.header("Content-Type", "application/json")
.body(r#"{"events": [{"event": "sample", "distinct_id": "sample"}]}"#)
.send()
.await?;
println!("{}", resp.text().await?);
Ok(())
}2.5analytics.group
关联群组
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
distinct_id | string | Required | 要关联到群组的用户 distinct_id。 |
group_type | string | Required | 群组维度,例如 company / team。 |
group_key | string | Required | 在 group_type 下的群组标识符。 |
traits | Record<string, unknown> | Optional | 可选的群组档案属性。 |
idempotency_key | string | Optional | 可选幂等键,确保重复请求只生效一次。 |
Returns
{ ok: boolean }| Name | Type | Description |
|---|---|---|
distinct_id | string | Distinct identifier for the user or entity |
group_type | string | Type of the analytics group |
group_key | string | Key of the analytics group |
Example
一次性前置(每个范例都假定已完成):
# No SDK to install — every call is a plain HTTPS request.
# Get a project key by signing in at https://infrai.cc/login (Google/GitHub gives
# you $2 free credit; email sign-in starts at $0). On 402 INSUFFICIENT_CREDIT, add
# funds at https://infrai.cc/billing (or POST /v1/account/topup and open the
# returned checkout_url).
export INFRAI_API_KEY="ifr_..."curl -X POST https://api.infrai.cc/v1/analytics/group \
-H "Authorization: Bearer $INFRAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{"distinct_id": "sample", "group_type": "sample", "group_key": "sample"}'# Zero-install REST call — no SDK required (short-term the API is REST-only).
import os, requests
resp = requests.post(
"https://api.infrai.cc/v1/analytics/group",
headers={
"Authorization": f"Bearer {os.environ['INFRAI_API_KEY']}",
},
json={'distinct_id': 'sample', 'group_type': 'sample', 'group_key': 'sample'},
)
resp.raise_for_status()
print(resp.json())// Zero-install REST call — no SDK required (short-term the API is REST-only).
const resp = await fetch(
"https://api.infrai.cc/v1/analytics/group",
{
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.INFRAI_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({"distinct_id": "sample", "group_type": "sample", "group_key": "sample"}),
},
);
console.log(await resp.json());// Zero-install REST call — no SDK required (short-term the API is REST-only).
const resp = await fetch(
"https://api.infrai.cc/v1/analytics/group",
{
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.INFRAI_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({"distinct_id": "sample", "group_type": "sample", "group_key": "sample"}),
},
);
if (!resp.ok) throw new Error(`infrai ${resp.status}`);
const data: unknown = await resp.json();
console.log(data);// Zero-install REST call — no SDK required (short-term the API is REST-only).
package main
import (
"bytes"
"fmt"
"net/http"
"os"
)
func main() {
body := []byte(`{"distinct_id": "sample", "group_type": "sample", "group_key": "sample"}`)
req, _ := http.NewRequest("POST", "https://api.infrai.cc/v1/analytics/group", bytes.NewReader(body))
req.Header.Set("Authorization", "Bearer "+os.Getenv("INFRAI_API_KEY"))
req.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
fmt.Println(resp.Status)
}// Zero-install REST call — no SDK required (short-term the API is REST-only).
import java.net.URI;
import java.net.http.*;
HttpRequest req = HttpRequest.newBuilder()
.uri(URI.create("https://api.infrai.cc/v1/analytics/group"))
.header("Authorization", "Bearer " + System.getenv("INFRAI_API_KEY"))
.header("Content-Type", "application/json")
.method("POST", HttpRequest.BodyPublishers.ofString("{\"distinct_id\": \"sample\", \"group_type\": \"sample\", \"group_key\": \"sample\"}"))
.build();
HttpResponse<String> resp = HttpClient.newHttpClient()
.send(req, HttpResponse.BodyHandlers.ofString());
System.out.println(resp.body());// Zero-install REST call — no SDK required (short-term the API is REST-only).
using System;
using System.Net.Http;
var client = new HttpClient();
var req = new HttpRequestMessage(new HttpMethod("POST"), "https://api.infrai.cc/v1/analytics/group");
var key = Environment.GetEnvironmentVariable("INFRAI_API_KEY");
req.Headers.Add("Authorization", "Bearer " + key);
req.Content = new StringContent("{\"distinct_id\": \"sample\", \"group_type\": \"sample\", \"group_key\": \"sample\"}", System.Text.Encoding.UTF8, "application/json");
var resp = await client.SendAsync(req);
Console.WriteLine(await resp.Content.ReadAsStringAsync());<?php
// Zero-install REST call — no SDK required (short-term the API is REST-only).
$ch = curl_init("https://api.infrai.cc/v1/analytics/group");
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
"Authorization: Bearer " . getenv("INFRAI_API_KEY"),
"Content-Type: application/json",
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, "{\"distinct_id\": \"sample\", \"group_type\": \"sample\", \"group_key\": \"sample\"}");
$response = curl_exec($ch);
curl_close($ch);
echo $response;# Zero-install REST call — no SDK required (short-term the API is REST-only).
require "net/http"
require "uri"
uri = URI("https://api.infrai.cc/v1/analytics/group")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
req = Net::HTTP::Post.new(uri)
req["Authorization"] = "Bearer #{ENV['INFRAI_API_KEY']}"
req["Content-Type"] = "application/json"
req.body = '{"distinct_id": "sample", "group_type": "sample", "group_key": "sample"}'
res = http.request(req)
puts res.body// Zero-install REST call — no SDK required (short-term the API is REST-only). (uses the reqwest + tokio crates)
use std::env;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let resp = reqwest::Client::new()
.post("https://api.infrai.cc/v1/analytics/group")
.header("Authorization", format!("Bearer {}", env::var("INFRAI_API_KEY")?))
.header("Content-Type", "application/json")
.body(r#"{"distinct_id": "sample", "group_type": "sample", "group_key": "sample"}"#)
.send()
.await?;
println!("{}", resp.text().await?);
Ok(())
}2.6analytics.query.events
查询原始事件
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
since | string | Required | 时间窗口起点(含)。format: date-time |
until | string | Required | 时间窗口终点(不含)。format: date-time |
filter | Record<string, unknown> | Optional | 可选属性过滤(键/值匹配)。 |
limit | number | Optional | 本页返回的最大条数(1-1000,默认 1000)。1–1000default: 1000 |
cursor | string | Optional | 来自上一页 next_cursor 的不透明游标。 |
Returns
EventQueryResult { events: object[], next_cursor?: string }| Name | Type | Description |
|---|---|---|
items | any[] | Array of result items in this page |
next_cursor | string | null | Opaque cursor to fetch the next page; null/absent if this is the last page |
total_estimate | integer | null | Estimated total number of matching events≥ 0 |
Example
一次性前置(每个范例都假定已完成):
# No SDK to install — every call is a plain HTTPS request.
# Get a project key by signing in at https://infrai.cc/login (Google/GitHub gives
# you $2 free credit; email sign-in starts at $0). On 402 INSUFFICIENT_CREDIT, add
# funds at https://infrai.cc/billing (or POST /v1/account/topup and open the
# returned checkout_url).
export INFRAI_API_KEY="ifr_..."curl -X POST https://api.infrai.cc/v1/analytics/query/events \
-H "Authorization: Bearer $INFRAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{"since": "sample", "until": "sample"}'# Zero-install REST call — no SDK required (short-term the API is REST-only).
import os, requests
resp = requests.post(
"https://api.infrai.cc/v1/analytics/query/events",
headers={
"Authorization": f"Bearer {os.environ['INFRAI_API_KEY']}",
},
json={'since': 'sample', 'until': 'sample'},
)
resp.raise_for_status()
print(resp.json())// Zero-install REST call — no SDK required (short-term the API is REST-only).
const resp = await fetch(
"https://api.infrai.cc/v1/analytics/query/events",
{
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.INFRAI_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({"since": "sample", "until": "sample"}),
},
);
console.log(await resp.json());// Zero-install REST call — no SDK required (short-term the API is REST-only).
const resp = await fetch(
"https://api.infrai.cc/v1/analytics/query/events",
{
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.INFRAI_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({"since": "sample", "until": "sample"}),
},
);
if (!resp.ok) throw new Error(`infrai ${resp.status}`);
const data: unknown = await resp.json();
console.log(data);// Zero-install REST call — no SDK required (short-term the API is REST-only).
package main
import (
"bytes"
"fmt"
"net/http"
"os"
)
func main() {
body := []byte(`{"since": "sample", "until": "sample"}`)
req, _ := http.NewRequest("POST", "https://api.infrai.cc/v1/analytics/query/events", bytes.NewReader(body))
req.Header.Set("Authorization", "Bearer "+os.Getenv("INFRAI_API_KEY"))
req.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
fmt.Println(resp.Status)
}// Zero-install REST call — no SDK required (short-term the API is REST-only).
import java.net.URI;
import java.net.http.*;
HttpRequest req = HttpRequest.newBuilder()
.uri(URI.create("https://api.infrai.cc/v1/analytics/query/events"))
.header("Authorization", "Bearer " + System.getenv("INFRAI_API_KEY"))
.header("Content-Type", "application/json")
.method("POST", HttpRequest.BodyPublishers.ofString("{\"since\": \"sample\", \"until\": \"sample\"}"))
.build();
HttpResponse<String> resp = HttpClient.newHttpClient()
.send(req, HttpResponse.BodyHandlers.ofString());
System.out.println(resp.body());// Zero-install REST call — no SDK required (short-term the API is REST-only).
using System;
using System.Net.Http;
var client = new HttpClient();
var req = new HttpRequestMessage(new HttpMethod("POST"), "https://api.infrai.cc/v1/analytics/query/events");
var key = Environment.GetEnvironmentVariable("INFRAI_API_KEY");
req.Headers.Add("Authorization", "Bearer " + key);
req.Content = new StringContent("{\"since\": \"sample\", \"until\": \"sample\"}", System.Text.Encoding.UTF8, "application/json");
var resp = await client.SendAsync(req);
Console.WriteLine(await resp.Content.ReadAsStringAsync());<?php
// Zero-install REST call — no SDK required (short-term the API is REST-only).
$ch = curl_init("https://api.infrai.cc/v1/analytics/query/events");
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
"Authorization: Bearer " . getenv("INFRAI_API_KEY"),
"Content-Type: application/json",
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, "{\"since\": \"sample\", \"until\": \"sample\"}");
$response = curl_exec($ch);
curl_close($ch);
echo $response;# Zero-install REST call — no SDK required (short-term the API is REST-only).
require "net/http"
require "uri"
uri = URI("https://api.infrai.cc/v1/analytics/query/events")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
req = Net::HTTP::Post.new(uri)
req["Authorization"] = "Bearer #{ENV['INFRAI_API_KEY']}"
req["Content-Type"] = "application/json"
req.body = '{"since": "sample", "until": "sample"}'
res = http.request(req)
puts res.body// Zero-install REST call — no SDK required (short-term the API is REST-only). (uses the reqwest + tokio crates)
use std::env;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let resp = reqwest::Client::new()
.post("https://api.infrai.cc/v1/analytics/query/events")
.header("Authorization", format!("Bearer {}", env::var("INFRAI_API_KEY")?))
.header("Content-Type", "application/json")
.body(r#"{"since": "sample", "until": "sample"}"#)
.send()
.await?;
println!("{}", resp.text().await?);
Ok(())
}2.7analytics.query.retention
查询留存
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
born_event | string | Required | 定义群组归属(第 0 天)的事件。 |
return_event | string | Required | 其再次发生用于衡量留存的事件。 |
since | string | Required | 时间窗口起点。format: date-time |
until | string | Required | 时间窗口终点。format: date-time |
interval | "day" | "week" | "month" | Optional | 分桶周期(默认 day)。default: "day" |
Returns
RetentionResult { matrix: number[][] }| Name | Type | Description |
|---|---|---|
cohorts | object[] | Retention cohort data points |
cohorts[].date | string | -format: date |
cohorts[].total | integer | -≥ 0 |
cohorts[].returning | object[] | - |
cohorts[].returning[].interval | integer | -≥ 0 |
cohorts[].returning[].n | integer | -≥ 0 |
Example
一次性前置(每个范例都假定已完成):
# No SDK to install — every call is a plain HTTPS request.
# Get a project key by signing in at https://infrai.cc/login (Google/GitHub gives
# you $2 free credit; email sign-in starts at $0). On 402 INSUFFICIENT_CREDIT, add
# funds at https://infrai.cc/billing (or POST /v1/account/topup and open the
# returned checkout_url).
export INFRAI_API_KEY="ifr_..."curl -X POST https://api.infrai.cc/v1/analytics/query/retention \
-H "Authorization: Bearer $INFRAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{"born_event": "sample", "return_event": "sample", "since": "sample", "until": "sample"}'# Zero-install REST call — no SDK required (short-term the API is REST-only).
import os, requests
resp = requests.post(
"https://api.infrai.cc/v1/analytics/query/retention",
headers={
"Authorization": f"Bearer {os.environ['INFRAI_API_KEY']}",
},
json={'born_event': 'sample', 'return_event': 'sample', 'since': 'sample', 'until': 'sample'},
)
resp.raise_for_status()
print(resp.json())// Zero-install REST call — no SDK required (short-term the API is REST-only).
const resp = await fetch(
"https://api.infrai.cc/v1/analytics/query/retention",
{
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.INFRAI_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({"born_event": "sample", "return_event": "sample", "since": "sample", "until": "sample"}),
},
);
console.log(await resp.json());// Zero-install REST call — no SDK required (short-term the API is REST-only).
const resp = await fetch(
"https://api.infrai.cc/v1/analytics/query/retention",
{
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.INFRAI_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({"born_event": "sample", "return_event": "sample", "since": "sample", "until": "sample"}),
},
);
if (!resp.ok) throw new Error(`infrai ${resp.status}`);
const data: unknown = await resp.json();
console.log(data);// Zero-install REST call — no SDK required (short-term the API is REST-only).
package main
import (
"bytes"
"fmt"
"net/http"
"os"
)
func main() {
body := []byte(`{"born_event": "sample", "return_event": "sample", "since": "sample", "until": "sample"}`)
req, _ := http.NewRequest("POST", "https://api.infrai.cc/v1/analytics/query/retention", bytes.NewReader(body))
req.Header.Set("Authorization", "Bearer "+os.Getenv("INFRAI_API_KEY"))
req.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
fmt.Println(resp.Status)
}// Zero-install REST call — no SDK required (short-term the API is REST-only).
import java.net.URI;
import java.net.http.*;
HttpRequest req = HttpRequest.newBuilder()
.uri(URI.create("https://api.infrai.cc/v1/analytics/query/retention"))
.header("Authorization", "Bearer " + System.getenv("INFRAI_API_KEY"))
.header("Content-Type", "application/json")
.method("POST", HttpRequest.BodyPublishers.ofString("{\"born_event\": \"sample\", \"return_event\": \"sample\", \"since\": \"sample\", \"until\": \"sample\"}"))
.build();
HttpResponse<String> resp = HttpClient.newHttpClient()
.send(req, HttpResponse.BodyHandlers.ofString());
System.out.println(resp.body());// Zero-install REST call — no SDK required (short-term the API is REST-only).
using System;
using System.Net.Http;
var client = new HttpClient();
var req = new HttpRequestMessage(new HttpMethod("POST"), "https://api.infrai.cc/v1/analytics/query/retention");
var key = Environment.GetEnvironmentVariable("INFRAI_API_KEY");
req.Headers.Add("Authorization", "Bearer " + key);
req.Content = new StringContent("{\"born_event\": \"sample\", \"return_event\": \"sample\", \"since\": \"sample\", \"until\": \"sample\"}", System.Text.Encoding.UTF8, "application/json");
var resp = await client.SendAsync(req);
Console.WriteLine(await resp.Content.ReadAsStringAsync());<?php
// Zero-install REST call — no SDK required (short-term the API is REST-only).
$ch = curl_init("https://api.infrai.cc/v1/analytics/query/retention");
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
"Authorization: Bearer " . getenv("INFRAI_API_KEY"),
"Content-Type: application/json",
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, "{\"born_event\": \"sample\", \"return_event\": \"sample\", \"since\": \"sample\", \"until\": \"sample\"}");
$response = curl_exec($ch);
curl_close($ch);
echo $response;# Zero-install REST call — no SDK required (short-term the API is REST-only).
require "net/http"
require "uri"
uri = URI("https://api.infrai.cc/v1/analytics/query/retention")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
req = Net::HTTP::Post.new(uri)
req["Authorization"] = "Bearer #{ENV['INFRAI_API_KEY']}"
req["Content-Type"] = "application/json"
req.body = '{"born_event": "sample", "return_event": "sample", "since": "sample", "until": "sample"}'
res = http.request(req)
puts res.body// Zero-install REST call — no SDK required (short-term the API is REST-only). (uses the reqwest + tokio crates)
use std::env;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let resp = reqwest::Client::new()
.post("https://api.infrai.cc/v1/analytics/query/retention")
.header("Authorization", format!("Bearer {}", env::var("INFRAI_API_KEY")?))
.header("Content-Type", "application/json")
.body(r#"{"born_event": "sample", "return_event": "sample", "since": "sample", "until": "sample"}"#)
.send()
.await?;
println!("{}", resp.text().await?);
Ok(())
}2.8analytics.query.path
查询行为路径
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
start_event | string | Required | 路径树展开的根事件。 |
since | string | Required | 时间窗口起点。format: date-time |
until | string | Required | 时间窗口终点。format: date-time |
max_depth | number | Optional | 路径树最大深度(1-20,默认 5)。1–20default: 5 |
Returns
PathResult { root: string, children: object[] }| Name | Type | Description |
|---|---|---|
root | string | Root node of the path tree |
children | object[] | Child nodes in the path tree |
children[].event | string | - |
children[].users | integer | -≥ 0 |
children[].children | object[] | - |
Example
一次性前置(每个范例都假定已完成):
# No SDK to install — every call is a plain HTTPS request.
# Get a project key by signing in at https://infrai.cc/login (Google/GitHub gives
# you $2 free credit; email sign-in starts at $0). On 402 INSUFFICIENT_CREDIT, add
# funds at https://infrai.cc/billing (or POST /v1/account/topup and open the
# returned checkout_url).
export INFRAI_API_KEY="ifr_..."curl -X POST https://api.infrai.cc/v1/analytics/query/path \
-H "Authorization: Bearer $INFRAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{"start_event": "sample", "since": "sample", "until": "sample"}'# Zero-install REST call — no SDK required (short-term the API is REST-only).
import os, requests
resp = requests.post(
"https://api.infrai.cc/v1/analytics/query/path",
headers={
"Authorization": f"Bearer {os.environ['INFRAI_API_KEY']}",
},
json={'start_event': 'sample', 'since': 'sample', 'until': 'sample'},
)
resp.raise_for_status()
print(resp.json())// Zero-install REST call — no SDK required (short-term the API is REST-only).
const resp = await fetch(
"https://api.infrai.cc/v1/analytics/query/path",
{
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.INFRAI_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({"start_event": "sample", "since": "sample", "until": "sample"}),
},
);
console.log(await resp.json());// Zero-install REST call — no SDK required (short-term the API is REST-only).
const resp = await fetch(
"https://api.infrai.cc/v1/analytics/query/path",
{
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.INFRAI_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({"start_event": "sample", "since": "sample", "until": "sample"}),
},
);
if (!resp.ok) throw new Error(`infrai ${resp.status}`);
const data: unknown = await resp.json();
console.log(data);// Zero-install REST call — no SDK required (short-term the API is REST-only).
package main
import (
"bytes"
"fmt"
"net/http"
"os"
)
func main() {
body := []byte(`{"start_event": "sample", "since": "sample", "until": "sample"}`)
req, _ := http.NewRequest("POST", "https://api.infrai.cc/v1/analytics/query/path", bytes.NewReader(body))
req.Header.Set("Authorization", "Bearer "+os.Getenv("INFRAI_API_KEY"))
req.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
fmt.Println(resp.Status)
}// Zero-install REST call — no SDK required (short-term the API is REST-only).
import java.net.URI;
import java.net.http.*;
HttpRequest req = HttpRequest.newBuilder()
.uri(URI.create("https://api.infrai.cc/v1/analytics/query/path"))
.header("Authorization", "Bearer " + System.getenv("INFRAI_API_KEY"))
.header("Content-Type", "application/json")
.method("POST", HttpRequest.BodyPublishers.ofString("{\"start_event\": \"sample\", \"since\": \"sample\", \"until\": \"sample\"}"))
.build();
HttpResponse<String> resp = HttpClient.newHttpClient()
.send(req, HttpResponse.BodyHandlers.ofString());
System.out.println(resp.body());// Zero-install REST call — no SDK required (short-term the API is REST-only).
using System;
using System.Net.Http;
var client = new HttpClient();
var req = new HttpRequestMessage(new HttpMethod("POST"), "https://api.infrai.cc/v1/analytics/query/path");
var key = Environment.GetEnvironmentVariable("INFRAI_API_KEY");
req.Headers.Add("Authorization", "Bearer " + key);
req.Content = new StringContent("{\"start_event\": \"sample\", \"since\": \"sample\", \"until\": \"sample\"}", System.Text.Encoding.UTF8, "application/json");
var resp = await client.SendAsync(req);
Console.WriteLine(await resp.Content.ReadAsStringAsync());<?php
// Zero-install REST call — no SDK required (short-term the API is REST-only).
$ch = curl_init("https://api.infrai.cc/v1/analytics/query/path");
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
"Authorization: Bearer " . getenv("INFRAI_API_KEY"),
"Content-Type: application/json",
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, "{\"start_event\": \"sample\", \"since\": \"sample\", \"until\": \"sample\"}");
$response = curl_exec($ch);
curl_close($ch);
echo $response;# Zero-install REST call — no SDK required (short-term the API is REST-only).
require "net/http"
require "uri"
uri = URI("https://api.infrai.cc/v1/analytics/query/path")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
req = Net::HTTP::Post.new(uri)
req["Authorization"] = "Bearer #{ENV['INFRAI_API_KEY']}"
req["Content-Type"] = "application/json"
req.body = '{"start_event": "sample", "since": "sample", "until": "sample"}'
res = http.request(req)
puts res.body// Zero-install REST call — no SDK required (short-term the API is REST-only). (uses the reqwest + tokio crates)
use std::env;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let resp = reqwest::Client::new()
.post("https://api.infrai.cc/v1/analytics/query/path")
.header("Authorization", format!("Bearer {}", env::var("INFRAI_API_KEY")?))
.header("Content-Type", "application/json")
.body(r#"{"start_event": "sample", "since": "sample", "until": "sample"}"#)
.send()
.await?;
println!("{}", resp.text().await?);
Ok(())
}3. All capabilities
Every routed capability in this module — the complete public REST contract. The methods above are the guided walkthrough; this index is the full reference.
analytics.aliasPOST /v1/analytics/aliasRename or merge an anonymous distinct_id (old_id) into a known identity (new_id).
Parameters (3)
| Name | Type | Required | Description |
|---|---|---|---|
old_id | string | Required | The distinct_id to rename from (e.g. anonymous id). |
new_id | string | Required | The canonical distinct_id to merge into. |
idempotency_key | string | null | Optional | Client-provided idempotency key; prevents duplicate execution on retry |
analytics.batchPOST /v1/analytics/batchIngest up to 1000 TrackEvent events in a single call (idempotency is per-event).
Parameters (1)
| Name | Type | Required | Description |
|---|---|---|---|
events | object[] | Required | Up to 1000 TrackEvent items.1–1000 items |
analytics.groupPOST /v1/analytics/groupAssociate a distinct_id with a group (organization/team/account) for B2B account-level aggregation.
Parameters (5)
| Name | Type | Required | Description |
|---|---|---|---|
distinct_id | string | Required | Distinct identifier for the user or entity |
group_type | string | Required | Group dimension, e.g. "company" / "team". |
group_key | string | Required | Group identifier within group_type. |
traits | object | null | Optional | Optional group profile traits. |
idempotency_key | string | null | Optional | Client-provided idempotency key; prevents duplicate execution on retry |
analytics.identifyPOST /v1/analytics/identifySet profile traits on a distinct_id, optionally merging a prior id via alias_for.
Parameters (4)
| Name | Type | Required | Description |
|---|---|---|---|
distinct_id | string | Required | Distinct identifier for the user or entity |
traits | object | null | Optional | Profile traits to merge onto the user. |
alias_for | string | null | Optional | Optional prior distinct_id to merge into this one at identify time. |
idempotency_key | string | null | Optional | Client-provided idempotency key; prevents duplicate execution on retry |
analytics.query.eventsPOST /v1/analytics/query/eventsQuery raw events within a time window, with attribute filters and cursor pagination.
Parameters (5)
| Name | Type | Required | Description |
|---|---|---|---|
since | string | Required | Window start (inclusive).format: date-time |
until | string | Required | Window end (exclusive).format: date-time |
filter | object | null | Optional | Optional property filter (key/value match). |
limit | integer | Optional | Maximum number of items to return per page1–1000default: 1000 |
cursor | string | null | Optional | Opaque cursor from a prior page's next_cursor. |
analytics.query.pathPOST /v1/analytics/query/pathBuild behavioral path/sequence trees rooted at a start event within a time window.
Parameters (4)
| Name | Type | Required | Description |
|---|---|---|---|
start_event | string | Required | Root event the path tree branches from. |
since | string | Required | ISO 8601 date when the current tier or state became effectiveformat: date-time |
until | string | Required | ISO 8601 date/time for the end of the query rangeformat: date-time |
max_depth | integer | Optional | Maximum depth of the path tree to return1–20default: 5 |
analytics.query.retentionPOST /v1/analytics/query/retentionCompute a retention matrix bucketed by period from a born event to a return event.
Parameters (5)
| Name | Type | Required | Description |
|---|---|---|---|
born_event | string | Required | Event that defines cohort membership (day 0). |
return_event | string | Required | Event whose recurrence defines retention. |
since | string | Required | ISO 8601 date when the current tier or state became effectiveformat: date-time |
until | string | Required | ISO 8601 date/time for the end of the query rangeformat: date-time |
interval | "day" | "week" | "month" | Optional | Time interval for retention buckets (e.g. day, week)default: "day" |
analytics.trackPOST /v1/analytics/trackIngest a single product analytics event with properties for a distinct user; idempotent.
Parameters (6)
| Name | Type | Required | Description |
|---|---|---|---|
event | string | Required | Event name you are recording (e.g. 'signup', 'purchase') — the verb of the action.pattern: ^[a-zA-Z][a-zA-Z0-9_.-]{0,127}$ |
distinct_id | string | Required | Distinct identifier for the user or entity |
properties | object | null | Optional | Additional properties for risk assessment |
timestamp | string | null | Optional | Unix timestamp of the data pointformat: date-time |
idempotency_key | string | null | Optional | Client-provided idempotency key; prevents duplicate execution on retry |
context | object | null | Optional | {ip, ua, session_id} |
4. End-to-end example
A production-style walkthrough of this module: configure once, then run the flow. It exercises most of the module's APIs.
A copy-paste-runnable single-file Python program (stdlib only, no SDK): set your INFRAI_API_KEY, run it, and walk this module's core flow with REAL billed calls — later steps reuse real fields returned by earlier ones. The 12-line helper is the entire integration.
#!/usr/bin/env python3
"""Infrai · analytics — runnable real-app example (single file, zero deps).
Copy this file, set your key, run it: every step is a REAL call to
api.infrai.cc, billed at the real (tiny) per-call price, printing the
live JSON response. Get a key at https://infrai.cc/login (Google/
GitHub sign-in grants $2 free credit); add funds at
https://infrai.cc/billing. No SDK — the 12-line helper below is the
entire integration."""
import json
import os
from urllib import error, request
KEY = os.environ.get("INFRAI_API_KEY") or "ifr_..." # <- your key
BASE = "https://api.infrai.cc"
# Same raw HTTPS POST/GET as every per-method example on this page —
# wrapped once for reuse. There is nothing else to it: no SDK.
def infrai(method, path, body=None):
req = request.Request(
BASE + path, method=method,
data=json.dumps(body).encode() if body is not None else None,
headers={"Authorization": f"Bearer {KEY}",
"Content-Type": "application/json"})
try:
with request.urlopen(req, timeout=60) as r:
return json.loads(r.read())
except error.HTTPError as e:
return json.loads(e.read())
def show(label, resp):
print(f"\n== {label} ==")
print(json.dumps(resp, indent=2, ensure_ascii=False))
return resp
# 1) analytics.track — POST /v1/analytics/track · Ingest a single product analytics event with properties for a distinct user; idempotent.
r1 = show("analytics.track", infrai("POST", "/v1/analytics/track", {"event":"checkout_completed","distinct_id":"user_42","properties":{"amount":19.99}}))
# 2) analytics.identify — POST /v1/analytics/identify · Set profile traits on a distinct_id, optionally merging a prior id via alias_for.
r2 = show("analytics.identify", infrai("POST", "/v1/analytics/identify", {"distinct_id":"sample"}))
一次性前置(每个范例都假定已完成):
# No SDK to install — every call is a plain HTTPS request.
# Get a project key by signing in at https://infrai.cc/login (Google/GitHub gives
# you $2 free credit; email sign-in starts at $0). On 402 INSUFFICIENT_CREDIT, add
# funds at https://infrai.cc/billing (or POST /v1/account/topup and open the
# returned checkout_url).
export INFRAI_API_KEY="ifr_..."# 1) Auth: every call is a raw HTTPS request to the Infrai gateway carrying
# only your project key. No SDK, no install.
# Get your key: sign in with Google/GitHub at https://infrai.cc/login for a
# project key + $2 free credit (email sign-in starts at $0). On 402
# INSUFFICIENT_CREDIT, add funds at https://infrai.cc/billing (or POST
# /v1/account/topup and open the returned checkout_url).
export INFRAI_API_KEY="ifr_..." # from https://infrai.cc/login
# 2) analytics.track
curl -X POST https://api.infrai.cc/v1/analytics/track \
-H "Authorization: Bearer $INFRAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{"event": "checkout_completed", "distinct_id": "user_42", "properties": {"amount": 19.99}}'
# 3) analytics.identify
curl -X POST https://api.infrai.cc/v1/analytics/identify \
-H "Authorization: Bearer $INFRAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{"distinct_id": "sample"}'
# 4) analytics.alias
curl -X POST https://api.infrai.cc/v1/analytics/alias \
-H "Authorization: Bearer $INFRAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{"old_id": "sample", "new_id": "sample"}'
# 5) analytics.batch
curl -X POST https://api.infrai.cc/v1/analytics/batch \
-H "Authorization: Bearer $INFRAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{"events": [{"event": "sample", "distinct_id": "sample"}]}'
# 6) analytics.group
curl -X POST https://api.infrai.cc/v1/analytics/group \
-H "Authorization: Bearer $INFRAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{"distinct_id": "sample", "group_type": "sample", "group_key": "sample"}'
# 1) Auth: every call is a raw HTTPS request carrying only your project key.
# No SDK to install — just the `requests` library.
import os, requests
BASE = "https://api.infrai.cc"
HEADERS = {
"Authorization": f"Bearer {os.environ['INFRAI_API_KEY']}",
"Content-Type": "application/json",
}
# 2) analytics.track
# Zero-install REST call — no SDK required (short-term the API is REST-only).
import os, requests
resp = requests.post(
"https://api.infrai.cc/v1/analytics/track",
headers={
"Authorization": f"Bearer {os.environ['INFRAI_API_KEY']}",
},
json={'event': 'checkout_completed', 'distinct_id': 'user_42', 'properties': {'amount': 19.99}},
)
resp.raise_for_status()
print(resp.json())
# 3) analytics.identify
# Zero-install REST call — no SDK required (short-term the API is REST-only).
import os, requests
resp = requests.post(
"https://api.infrai.cc/v1/analytics/identify",
headers={
"Authorization": f"Bearer {os.environ['INFRAI_API_KEY']}",
},
json={'distinct_id': 'sample'},
)
resp.raise_for_status()
print(resp.json())
# 4) analytics.alias
# Zero-install REST call — no SDK required (short-term the API is REST-only).
import os, requests
resp = requests.post(
"https://api.infrai.cc/v1/analytics/alias",
headers={
"Authorization": f"Bearer {os.environ['INFRAI_API_KEY']}",
},
json={'old_id': 'sample', 'new_id': 'sample'},
)
resp.raise_for_status()
print(resp.json())
# 5) analytics.batch
# Zero-install REST call — no SDK required (short-term the API is REST-only).
import os, requests
resp = requests.post(
"https://api.infrai.cc/v1/analytics/batch",
headers={
"Authorization": f"Bearer {os.environ['INFRAI_API_KEY']}",
},
json={'events': [{'event': 'sample', 'distinct_id': 'sample'}]},
)
resp.raise_for_status()
print(resp.json())
# 6) analytics.group
# Zero-install REST call — no SDK required (short-term the API is REST-only).
import os, requests
resp = requests.post(
"https://api.infrai.cc/v1/analytics/group",
headers={
"Authorization": f"Bearer {os.environ['INFRAI_API_KEY']}",
},
json={'distinct_id': 'sample', 'group_type': 'sample', 'group_key': 'sample'},
)
resp.raise_for_status()
print(resp.json())
// 1) Auth: every call is a raw HTTPS request carrying only your project key.
// No SDK to install — just the built-in fetch().
const BASE = "https://api.infrai.cc";
const HEADERS = {
"Authorization": `Bearer ${process.env.INFRAI_API_KEY}`,
"Content-Type": "application/json",
};
// 2) analytics.track
// Zero-install REST call — no SDK required (short-term the API is REST-only).
const resp = await fetch(
"https://api.infrai.cc/v1/analytics/track",
{
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.INFRAI_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({"event": "checkout_completed", "distinct_id": "user_42", "properties": {"amount": 19.99}}),
},
);
console.log(await resp.json());
// 3) analytics.identify
// Zero-install REST call — no SDK required (short-term the API is REST-only).
const resp = await fetch(
"https://api.infrai.cc/v1/analytics/identify",
{
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.INFRAI_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({"distinct_id": "sample"}),
},
);
console.log(await resp.json());
// 4) analytics.alias
// Zero-install REST call — no SDK required (short-term the API is REST-only).
const resp = await fetch(
"https://api.infrai.cc/v1/analytics/alias",
{
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.INFRAI_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({"old_id": "sample", "new_id": "sample"}),
},
);
console.log(await resp.json());
// 5) analytics.batch
// Zero-install REST call — no SDK required (short-term the API is REST-only).
const resp = await fetch(
"https://api.infrai.cc/v1/analytics/batch",
{
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.INFRAI_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({"events": [{"event": "sample", "distinct_id": "sample"}]}),
},
);
console.log(await resp.json());
// 6) analytics.group
// Zero-install REST call — no SDK required (short-term the API is REST-only).
const resp = await fetch(
"https://api.infrai.cc/v1/analytics/group",
{
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.INFRAI_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({"distinct_id": "sample", "group_type": "sample", "group_key": "sample"}),
},
);
console.log(await resp.json());
// 1) Auth: every call is a raw HTTPS request carrying only your project key.
// No SDK to install — just the built-in fetch(), typed.
const BASE = "https://api.infrai.cc";
const HEADERS: Record<string, string> = {
"Authorization": `Bearer ${process.env.INFRAI_API_KEY}`,
"Content-Type": "application/json",
};
// 2) analytics.track
// Zero-install REST call — no SDK required (short-term the API is REST-only).
const resp = await fetch(
"https://api.infrai.cc/v1/analytics/track",
{
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.INFRAI_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({"event": "checkout_completed", "distinct_id": "user_42", "properties": {"amount": 19.99}}),
},
);
if (!resp.ok) throw new Error(`infrai ${resp.status}`);
const data: unknown = await resp.json();
console.log(data);
// 3) analytics.identify
// Zero-install REST call — no SDK required (short-term the API is REST-only).
const resp = await fetch(
"https://api.infrai.cc/v1/analytics/identify",
{
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.INFRAI_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({"distinct_id": "sample"}),
},
);
if (!resp.ok) throw new Error(`infrai ${resp.status}`);
const data: unknown = await resp.json();
console.log(data);
// 4) analytics.alias
// Zero-install REST call — no SDK required (short-term the API is REST-only).
const resp = await fetch(
"https://api.infrai.cc/v1/analytics/alias",
{
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.INFRAI_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({"old_id": "sample", "new_id": "sample"}),
},
);
if (!resp.ok) throw new Error(`infrai ${resp.status}`);
const data: unknown = await resp.json();
console.log(data);
// 5) analytics.batch
// Zero-install REST call — no SDK required (short-term the API is REST-only).
const resp = await fetch(
"https://api.infrai.cc/v1/analytics/batch",
{
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.INFRAI_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({"events": [{"event": "sample", "distinct_id": "sample"}]}),
},
);
if (!resp.ok) throw new Error(`infrai ${resp.status}`);
const data: unknown = await resp.json();
console.log(data);
// 6) analytics.group
// Zero-install REST call — no SDK required (short-term the API is REST-only).
const resp = await fetch(
"https://api.infrai.cc/v1/analytics/group",
{
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.INFRAI_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({"distinct_id": "sample", "group_type": "sample", "group_key": "sample"}),
},
);
if (!resp.ok) throw new Error(`infrai ${resp.status}`);
const data: unknown = await resp.json();
console.log(data);