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.
Weekly league with item rewards
A three-tier weekly league scored by your backend, paying gems and items for top ranks and promotion, with promotion messages.
Push through your own OneSignal
Send Orishare engagement messages (streak at risk, league promotion, friend nudges) as push notifications through your own OneSignal app.