Orishare
Recipes

Friend streak with milestones

A daily streak two friends keep together, fed by a rule from app events, with milestone rewards and an at-risk reminder.

The result: when two friends both complete a lesson on the same day their shared streak grows by one; at 7 days both get a streak freeze item and at 30 days both get 300 XP. In the evening, a player whose friend is waiting on them gets a reminder. See Friends and teams for the rules.

You need: an event your app already sends (here lesson.completed, client-allowed if the app sends it itself), the currency xp, and players who are friends (signed-in players add each other by friend code).

1. Propose the definition

{
  "commands": [
    {
      "type": "friend_streak_definition.create",
      "key": "duo_streak",
      "name": "Friend streak",
      "config": {
        "schema": "friend_streak/v1",
        "timezone": "environment",
        "milestones": [
          { "length": 7, "reward": [{ "type": "item", "item": "streak_freeze", "quantity": 1 }] },
          { "length": 30, "reward": [{ "currency": "xp", "amount": 300 }] }
        ]
      }
    }
  ]
}

Send it with POST /v1/change_sets and apply or confirm it, then activate: { "type": "friend_streak_definition.activate", "key": "duo_streak", "expected_version": <revision> } (read the revision from GET /v1/friend_streak_definitions). In a test environment you may use POST /v1/friend_streak_definitions and POST /v1/friend_streak_definitions/{id}/activate directly.

2. Feed it with a rule

Create the rule with POST /v1/rules (or the rule.create change-set command) and publish it:

{
  "name": "A lesson keeps the friend streak",
  "definition": {
    "schema": "orishare.rule/v2",
    "trigger": { "kind": "customer_event", "event": "lesson.completed" },
    "actions": [{ "type": "friend_streak.activity", "friend_streak": "duo_streak" }]
  }
}

Each lesson.completed marks the player active today (once per day, whatever the number of lessons). Every friend who was also active today extends their pair's streak.

Lessons sent by the app itself (POST /v1/customer/events) are browser claims, and a browser claim never feeds a definition that pays a monetary currency. While the environment's trust policy is empty every currency counts as monetary, so either pay milestones in items only, or list your real-money currencies once with PATCH /v1/trust_policy (If-Match set to the version from GET /v1/trust_policy), for example { "monetary_currencies": ["gems"], "caps": [] }, so that xp is not one of them. Lessons your backend sends with the secret key are not limited.

A backend can record activity directly instead: POST /v1/friend_streak_definitions/{id}/activities with { "customer_id" }.

3. Show it

GET /v1/customer/friend_streaks returns, per friend, length, longest, extended_today, at_risk and next_milestone with its reward:

const API = 'https://api.orishare.com';
const res = await fetch(`${API}/v1/customer/friend_streaks`, {
  credentials: 'omit',
  headers: { Authorization: `Bearer ${PUBLISHABLE_KEY}`, 'X-Orishare-Customer-Token': token },
});
for (const s of (await res.json()).data)
  render(`${s.friend.display_name}: ${s.length} days${s.at_risk ? ' (play today!)' : ''}`);

A streak whose last shared day is before yesterday shows length 0.

4. Remind the waiting friend

Create the message type friend_streak_at_risk (catalogue key):

{ "key": "friend_streak_at_risk", "routes": [{ "channel": "mobile_push", "path": "builtin" }] }

After 18:00 in the streak's zone, each pair with a streak of 2 or more where one friend has not played yet produces one friend_streak.at_risk event a day. Players can also nudge each other: POST /v1/customer/nudges with { "code": "<friend code>", "context": "streak" } and a friend_nudge message type.

5. Test in the test environment

Make two test players friends (POST /v1/customers/{id}/friendships with { "other_customer_id", "status": "accepted" }), send one lesson.completed for each on the same day and read GET /v1/customer/friend_streaks for either: length 1. Repeat on following days (with occurred_at on backend events, or POST /v1/friend_streak_definitions/{id}/activities with at) to reach a milestone, then check both players' balances.

On this page