Gamification primitive · feature guide

The streak API with real mechanics.

What is a streak api? A streak API is a backend service that tracks consecutive user engagement — daily or weekly — server-side. You define a qualifying event once; the API counts consecutive periods, applies grace hours before a break, consumes streak freezes on a missed period, and survives reinstalls and device switches, because the truth lives in the backend rather than on the phone.

Get an API key All featuresupdated June 12, 2026
the agent path:

Streaks look trivial — increment a counter once a day — and then the edge cases arrive: the user who finishes a session at 11:58pm and opens the app at 12:02am, the timezone flight, the two devices that qualify simultaneously, the outage that wrongly broke ten thousand streaks, the Duolingo-style freeze your PM wants for retention. Amba ships streaks as a declarative definition: a qualifying event, a daily or weekly period, grace hours, and a freeze (shield) economy with an auto-grant rule. Qualification is idempotent per period and concurrency-safe; a scheduled sweep detects misses, consumes a shield when the user holds one, and emits events your segments and push campaigns can react to. There is even a support tool for restoring a wrongly broken streak.

How do streak periods and day boundaries work?

A streak has a period of daily or weekly. Daily buckets are calendar days and weekly buckets are ISO weeks (Monday-start) — both anchored to UTC, so every user on Earth shares one consistent boundary and a qualification can never land in different buckets on the server and in the database. Qualifying is idempotent within a period: a second qualifying event the same day is acknowledged but does not double-increment. Honest limit, stated plainly: as of mid-2026 boundaries are UTC, not per-user local midnight — grace hours are the shipped cushion for late-night users, and the FAQ below covers how to reason about it.

How do grace periods work?

grace_period_hours extends the deadline before a miss becomes a break: a streak is only marked broken when the time since the LAST QUALIFICATION exceeds the period length plus the grace window. A daily streak with 6 grace hours that last qualified at 11pm UTC is safe until 5am UTC two days later — the window anchors to the last qualification, not to midnight. Breaks are detected by a scheduled evaluation that runs daily, shortly after the UTC day boundary; until it runs, the streak reads as active. Grace defers break detection — consecutive counting itself still uses calendar-day buckets.

How do streak freezes (shields) work?

Freezes are the forgiveness mechanic that keeps a long streak from dying to one bad day. Enable them with freeze_enabled, cap how many a user can hold with max_freezes, and optionally auto-grant one per N consecutive qualifying events with freezes_per_n_events (a restart after a break deliberately does not re-grant). When the daily sweep finds a missed period and the user holds a shield, it consumes one, sets the streak status to frozen instead of broken, and emits a streak_shielded event — so your app can render "your streak is safe" instead of a reset to zero.

What happens when a streak wrongly breaks?

Outages happen, and a broken 200-day streak is a support fire. amba_streaks_reset is the repair tool: it restores a specific user’s streak to a given count (or zeroes it for a clean restart) and marks it active again, with the longest count bumped if the restored value exceeds it. Every state transition — increment, reset, freeze — is also recorded in an audit trail, so support can see the full timeline before deciding.

The shipped streak definition schema
FieldTypeWhat it does
keystringStable handle the SDK qualifies with: Amba.streaks.qualify("daily_lesson"). Immutable after creation.
qualifying_eventstringThe tracked event that advances the streak (e.g. "lesson_completed").
period"daily" | "weekly"Bucket size. Daily = UTC calendar day; weekly = ISO week, Monday-start, UTC. Defaults to daily.
grace_period_hoursnumberExtra hours past the period boundary before a miss breaks the streak. Default 0.
freeze_enabledbooleanWhether a held freeze (shield) is consumed on a miss instead of breaking the streak.
max_freezesnumberCap on shields a user can hold concurrently.
freezes_per_n_eventsnumber | nullAuto-grant rule: 1 shield per N consecutive qualifying events, capped at max_freezes. Null disables.

Field names and defaults verified against the live tool registry and API source, June 2026.

how it works

How do I create a streak with the API?

One tool call defines the whole mechanic

amba_streaks_create
{ "project_id": "...",
  "key": "daily_lesson",
  "name": "Daily Lesson",
  "qualifying_event": "lesson_completed",
  "period": "daily",
  "grace_period_hours": 6,
  "freeze_enabled": true,
  "max_freezes": 2,
  "freezes_per_n_events": 5,
  "pat": "..." }

→ returns the streak definition; the SDK qualifies it by key.
   amba_streaks_update patches any field except the
   immutable key;
   amba_streaks_reset repairs a specific user's streak.

Argument names and semantics are from the live tool registry, June 2026 — nothing here is invented.

in the app

How does the app qualify and read a streak?

Qualify on every qualifying user action — idempotent per period

import { Amba } from '@layers/amba-web';

// When the user does the thing (finishes a lesson, logs a workout):
const streak = await Amba.streaks.qualify('daily_lesson');

streak.current_count; // 7  — consecutive periods
streak.longest_count; // 12 — personal best
streak.status; // 'active' | 'broken' | 'frozen'
streak.freezes_remaining; // 1  — unused shields in reserve

// Render every streak the user is tracking:
const all = await Amba.streaks.getAll();

Verified against the published SDK surface; identical shape on web, Node, React Native, Expo, and the native SDKs. Tracking the qualifying event also advances the streak automatically — explicit qualify() is for direct control.

the tools

Which MCP tools cover this surface?

toolwhat it does
amba_streaks_createDefine a streak: key, qualifying event, period, grace, freezes
amba_streaks_listList streak definitions for a project
amba_streaks_updatePatch any definition field except the immutable key; omitted fields untouched
amba_streaks_resetSupport repair: restore or zero one user’s streak
amba_streaks_deleteRemove a definition (user rows cascade)
the honest part

When is this not the right call?

When a local-only streak is fine
A single cosmetic streak on one device — no shields, no cross-device sync, no push or segment reacting to it, no support restores — can be a few lines of on-device date math. Take the backend when streaks must survive reinstall, sync across devices, drive re-engagement, or be repairable by support.
Day boundaries are UTC, not per-user local midnight
As of mid-2026, periods anchor to UTC for every user; a per-user timezone boundary is not a configuration option. Grace hours are the shipped mitigation — a daily streak with 6-8 grace hours absorbs the late-night-user problem for most apps. If strict local-midnight semantics are a hard product requirement, that is a real gap to weigh.
Breaks are detected by a daily sweep, not instantly
A missed streak is marked broken (or frozen) by a scheduled evaluation that runs daily after the UTC boundary — not at the exact second the period lapses. For UI that must flip to "broken" in real time at midnight, compute the display state client-side from last_qualified_at while the server remains the source of truth.
the agent path

Can an AI agent set this up end to end?

Yes. Amba’s hosted MCP server at https://mcp.amba.dev/mcp (Streamable HTTP) exposes the whole backend as tool calls. amba_developer_signup mints a developer token and a provisioned project — client key and server key included — with no browser, and the project goes active in about ten seconds. A habit app’s whole streak system — definition, shield economy, the event that drives it — is one amba_streaks_create call after signup; the agent then writes the qualify() call into the right user action.

questions

Streak APIFAQ

What is a streak API?

A backend service that tracks consecutive user engagement server-side. You define a qualifying event and a period (daily or weekly); the API counts consecutive periods, applies grace hours, manages freezes, and exposes current count, longest count, and status to your app — state that survives reinstalls because it does not live on the device.

How does Amba handle timezones for streaks?

Day boundaries are anchored to UTC for every user — daily buckets are UTC calendar days, weekly buckets are ISO weeks. That makes qualification deterministic and immune to device-clock games, but it is not per-user local midnight; grace hours (e.g. 6-8) are the shipped way to absorb late-night qualifications near the boundary.

What is a streak freeze and how is it earned?

A freeze (shield) is a consumable that protects a streak from one missed period: the sweep sets the streak to frozen and decrements the user’s shields instead of breaking it, emitting a streak_shielded event. Shields can be auto-granted — one per N consecutive qualifying events via freezes_per_n_events, capped at max_freezes. A restart after a break does not re-grant.

Can I restore a user’s streak after an outage?

Yes — amba_streaks_reset sets a specific user’s current count to any value (or zero for a clean restart) and marks the streak active again, bumping the longest count if exceeded. Every increment, reset, and freeze is also recorded in an audit trail, so support can verify what happened before repairing.

Do I have to call qualify() explicitly?

No. Tracking the qualifying event through the SDK advances the streak automatically — the event tracker checks streak definitions on every matching event. Explicit Amba.streaks.qualify("key") exists for direct control and returns the updated streak in the same call, which is convenient for rendering the new count immediately.

Are weekly streaks supported, or only daily?

Both. period is "daily" or "weekly"; weekly buckets follow ISO weeks (Monday-start, UTC), so qualifying on Monday and again the next Wednesday counts as consecutive weeks. Grace hours and freezes work identically for both periods.

sources

Sources for this guide

start in 30 seconds

Hand the docs to your agent.
Ship by lunch.

Read the docs