SDK API Client
Syntropy provides two client factories for different use cases:
| Client | Key type | Use case |
|---|---|---|
createSyntropyPublicClient | Publishable (syn_pk_) | Client-side apps (React Native, browser) -- identify, track, devices only |
createSyntropyApiClient | Secret (syn_sk_) | Server-side -- full admin access (list, segments, import, queue, etc.) |
Both clients are exported from:
@eclosion-tech/syntropy-node@eclosion-tech/syntropy-react-native@eclosion-tech/syntropy-nextjs@eclosion-tech/syntropy-express@eclosion-tech/syntropy-browser
Public Client (Client-Side)
Use createSyntropyPublicClient in React Native, browser, or any client-side code. Publishable keys are safe to embed -- they only grant access to customer write operations.
import { createSyntropyPublicClient } from "@eclosion-tech/syntropy-react-native";
const customers = createSyntropyPublicClient({
accountId: "project_uuid",
publishableKey: "syn_pk_xxx",
baseUrl: "https://syntropy.chat/api",
});
// Identify (upsert) a customer
await customers.identify({
externalId: "user_123",
email: "user@example.com",
name: "Jane Doe",
metadata: { plan: "pro" },
});
// Track an event
await customers.track({
name: "purchase_completed",
externalId: "user_123",
payload: { amount: 99.99, currency: "USD" },
});
// Register a push device
await customers.registerDevice({
externalId: "user_123",
platform: "ios",
pushToken: "expo_push_token",
active: true,
});
Public Endpoints
The public client calls these endpoints (CORS-enabled, rate-limited):
| Method | Endpoint | Scope |
|---|---|---|
POST | /api/{accountId}/customers/identify | customers:write |
POST | /api/{accountId}/customers/track | customer_events:write |
POST | /api/{accountId}/customers/devices | customer_devices:write |
Admin Client (Server-Side)
Use createSyntropyApiClient with a secret key for full access from backend services.
import { createSyntropyApiClient } from "@eclosion-tech/syntropy-node";
const api = createSyntropyApiClient({
baseUrl: "https://syntropy.chat/api",
apiKey: process.env.SYNTROPY_API_KEY,
});
const scope = {
organizationId: "org_uuid",
projectId: "project_uuid",
};
Source Maps
await api.sourceMaps.upload(scope, {
file, // Blob/File/Buffer-compatible form value in your runtime
version: "1.2.3",
filename: "main.js.map",
});
const { sourceMaps } = await api.sourceMaps.list(scope);
Chat Schemas
const created = await api.chatSchemas.create(scope, {
name: "Lead Intake v1",
schema: {
type: "object",
properties: {
name: { type: "string" },
email: { type: "string", format: "email" },
},
},
});
const { schemas } = await api.chatSchemas.list(scope);
await api.chatSchemas.update(scope, created.schema.id, {
description: "Updated schema description",
});
Customers
await api.customers.upsert(scope, {
externalId: "user_123",
email: "user@example.com",
name: "Jane Doe",
metadata: { plan: "pro" },
});
await api.customers.trackEvent(scope, {
name: "purchase_completed",
externalId: "user_123",
payload: { amount: 99.99, currency: "USD" },
});
await api.customers.registerDevice(scope, "customer_uuid", {
platform: "ios",
pushToken: "expo_push_token",
active: true,
});
Segments and Eligibility
await api.customers.upsertSegment(scope, {
name: "Pro Customers",
definition: {
logic: "and",
conditions: [
{ field: "status", operator: "eq", value: "active" },
{ field: "metadata.plan", operator: "eq", value: "pro" },
],
},
});
const eligibility = await api.customers.evaluateEligibility(scope, {
externalId: "user_123",
channel: "email",
topic: "product_updates",
});
CSV Import
await api.customers.importCsv(scope, {
csv: csvString,
hasHeader: true,
dryRun: false,
source: "customer_io_csv_import",
});
Shared Queue Jobs
Use queue APIs when producers should only need a project API key. Required scopes:
queue_jobs:write(orproject:admin) for enqueuequeue_jobs:read(orproject:admin) for monitoring
await api.queue.enqueue(scope, {
task: "alerts.process",
payload: {
trigger: "manual",
},
idempotencyKey: "syntropy:alerts.process:manual",
});
const { jobs } = await api.queue.list(scope, {
status: "running",
limit: 20,
});
const job = await api.queue.get(scope, "job_uuid", { eventLimit: 100 });
const { events } = await api.queue.listEvents(scope, {
since: new Date(Date.now() - 30_000).toISOString(),
});
Error Handling
The client throws SyntropyApiError for non-2xx responses.
import {
createSyntropyApiClient,
SyntropyApiError,
} from "@eclosion-tech/syntropy-node";
try {
await api.customers.list(scope);
} catch (error) {
if (error instanceof SyntropyApiError) {
console.error(error.status, error.responseBody);
}
}