Your agent can ship a working engagement loop this week

Documentation

Streakline is a REST API with thin SDKs and an agent-native setup flow. Send events, and scoring, levels, streaks, achievements, and leaderboards update for you. Most teams are live the same day.

Preview. The CLI, MCP server, and Agent Skills are early. The REST API and the TypeScript & Swift SDKs are the stable surfaces today.

Quickstart

Install the server SDK in your API, configure its OAuth M2M client, and mint a mobile credential for your app.

terminalbash
bun add @streakline/sdk   # or: npm install @streakline/sdk
server.tstypescript
import { StreaklineServer } from "@streakline/sdk/server";

const streakline = new StreaklineServer({
  clientId: process.env.STREAKLINE_CLIENT_ID!,
  clientSecret: process.env.STREAKLINE_CLIENT_SECRET!,
});

// Mint this from your API after your own auth and entitlement checks.
const credential = await streakline.createClientCredential({ userId: "user_123" });

// Trusted backend events use the OAuth M2M client directly.
await streakline.track("user_123", "subscription.started");

Authentication

Every request carries one Bearer credential. There are two credential types, and the difference matters:

  • Client credentials are fixed-scope, five-minute, user-bound credentials minted by your backend after its own session and entitlement checks. Mobile apps use one for the model, event batches, and the current user's profile.
  • OAuth M2M clients are server-only and scope trusted server operations. A client created without scopes receives exactly events:write. Keep client_credentials:issue on a separate, least-privilege BFF client: it must derive user_id from its authenticated customer session, because Streakline cannot authenticate that caller for you.
headerhttp
Authorization: Bearer $CLIENT_CREDENTIAL  # mobile calls
Authorization: Bearer $OAUTH_ACCESS_TOKEN  # server calls

Core concepts

The model has eleven composable primitives: Events, Score, Scopes, Levels, Streaks, Leaderboards, Balances, Store, Achievements, Challenges, and Grants. Events and Score are always enabled; every other capability is opt-in. See the complete primitive guide for the full picture.

CLI

The CLI inspects your repository and drafts a scoring model mapped to your real product journeys, then deploys it as a versioned config.

terminalbash
npx streakline init       # inspect repo → draft streakline.config.ts
npx streakline preview    # dry-run scoring against sample events
npx streakline deploy     # publish the active scoring version

MCP server

Connect your agent to Streakline's remote MCP resource to read projects and deployed config, inspect releases, and deploy versions without giving a desktop client a server secret. Your MCP client opens a browser for OAuth consent and uses authorization code with PKCE.

.mcp.jsonjson
{
  "mcpServers": {
    "streakline": {
      "type": "http",
      "url": "https://api.streakline.dev/mcp"
    }
  }
}

Ask a Workspace owner for a controlled public MCP client if your agent does not support automatic OAuth discovery. Dynamic client registration is disabled, and public clients never receive a client secret.

Agent Skills

Drop-in skills give Claude and other coding agents the recipes to wire gamification end-to-end — from mapping events to rendering the SDK in your UI. Point the agent at your repo and let it work.

TypeScript SDK

The server SDK wraps scoped OAuth M2M routes with full types. Use it only where you hold an OAuth client secret.

server.tstypescript
import { StreaklineServer } from "@streakline/sdk/server";

const streakline = new StreaklineServer({
  clientId: process.env.STREAKLINE_CLIENT_ID!,
  clientSecret: process.env.STREAKLINE_CLIENT_SECRET!,
});

const credential = await streakline.createClientCredential({ userId: "user_123" });

await streakline.track("user_123", "purchase.made", {
  idempotencyKey: "ord_991",
});

Swift / iOS SDK

Mobile SDKs accept a structured, short-lived credential from your backend. The SDK validates its subject and expiry before each request, and refreshes once only after a 401 response.

App.swiftswift
import Streakline

StreaklineSDK.shared.configure(userId: user.id) {
  let response = try await api.createStreaklineClientCredential()
  return StreaklineClientCredential(
    accessToken: response.access_token,
    userId: response.user_id,
    expiresAt: ISO8601DateFormatter().date(from: response.expires_at)!
  )
}

let result  = try await StreaklineSDK.shared.track(event: "lesson.completed")
let profile = try await StreaklineSDK.shared.profile()

REST

Every SDK is a thin wrapper over the same REST API. Secret routes stay on your API; each mobile request uses one user-bound client credential.

terminalbash
curl https://api.streakline.dev/api/v1/sdk/model \
  -H "Authorization: Bearer $CLIENT_CREDENTIAL" \

curl -X POST https://api.streakline.dev/api/v1/events/batch \
  -H "Authorization: Bearer $CLIENT_CREDENTIAL" \
  -H "Content-Type: application/json" \
  -d '{"events":[{"event_type":"lesson.completed"}]}'

API endpoints

The full v1 surface. Server routes require scoped OAuth M2M. Mobile model, event, and profile routes require one user-bound client credential.

POST/api/v1/client-credentialsHigh-privilege BFF minting with OAuth M2M
GET/api/v1/sdk/modelFetch the scoring model with a client credential
POST/api/v1/events/batchBatch mobile events with a client credential
GET/api/v1/me/profileCurrent user's score, level, streak
POST/api/v1/eventsTrack a trusted server event with OAuth M2M
GET/api/v1/users/:id/profileServer-side profile lookup with OAuth M2M
GET/api/v1/users/:id/achievementsUnlocked achievements

Open the full interactive reference ↗

Tech stack

Streakline is a Bun monorepo: the hosted API plus its data layer, with the SDKs and marketing site alongside.

Runtime
Bun
API
Hono
Database
PostgreSQL + Drizzle ORM
Auth
Better Auth + user-bound client credentials and OAuth M2M
Billing
Stripe
Web
Astro + React
SDKs
TypeScript · Swift · Kotlin
Monorepo
Turborepo + Bun workspaces
API docs
OpenAPI + Scalar