# Points Program with Leaderboard

Build a points-based loyalty program where users earn points for actions — with a leaderboard and per-user rewards view.

## Prerequisites

* A Fuul account with a project created
* Conversion events configured with point-based payouts
* API keys: `send:tracking_event` (frontend) and `send:trigger_event` (backend)

## Step 1: Install and initialize

```bash
npm install @fuul/sdk
```

```typescript
import { Fuul } from '@fuul/sdk';

Fuul.init({ apiKey: 'your-send-tracking-event-key' });
```

## Step 2: Track users

Set up pageview tracking and wallet identification so Fuul can attribute points to the right users:

```typescript
// On every page load
await Fuul.sendPageview();

// On wallet connect
await Fuul.identifyUser({
  identifier: address,
  identifierType: 'evm_address',
  signature,
  message: 'Sign to verify your identity',
});
```

See [Tracking Referrals](/developer-guide/tracking-referrals-in-your-app.md) for full details.

## Step 3: Send custom events from your backend

When a user completes an action that should earn points, send an event from your backend:

```typescript
// Backend — use the send:trigger_event API key
const response = await fetch('https://api.fuul.xyz/api/v1/events', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Authorization': 'Bearer your-send-trigger-event-key',
  },
  body: JSON.stringify({
    name: 'task_completed',
    user: {
      identifier: '0x1234...',
      identifier_type: 'evm_address',
    },
    args: {
      value: {
        amount: '100',
        currency: { name: 'POINT' },
      },
    },
  }),
});
```

**cURL equivalent:**

```bash
curl -X POST https://api.fuul.xyz/api/v1/events \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer your-send-trigger-event-key" \
  -d '{
    "name": "task_completed",
    "user": {
      "identifier": "0x1234...",
      "identifier_type": "evm_address"
    },
    "args": {
      "value": {
        "amount": "100",
        "currency": { "name": "POINT" }
      }
    }
  }'
```

{% hint style="danger" %}
Always send trigger events from the backend using a `send:trigger_event` key. Never expose this key in the frontend.
{% endhint %}

See [Sending Custom Events](/developer-guide/sending-custom-events-through-the-api.md) for batch events and advanced options.

## Step 4: Display the points leaderboard

```typescript
const leaderboard = await Fuul.getPointsLeaderboard({});
```

```json
{
  "total_results": 240,
  "page": 1,
  "page_size": 10,
  "results": [
    { "address": "0x1234...", "total_amount": 15000, "rank": 1, "total_attributions": 85 },
    { "address": "0x5678...", "total_amount": 12300, "rank": 2, "total_attributions": 62 }
  ]
}
```

{% hint style="info" %}
Leaderboard responses are paginated. Use `page` and `page_size` (max 100) to retrieve the full list.
{% endhint %}

## Step 5: Show a user's points

```typescript
const points = await Fuul.getPointsLeaderboard({
  user_identifier: address,
  identifier_type: 'evm_address',
});
// Shows the user's total points, rank, and attribution count
```

## Step 6: Show points history

Display a breakdown of how the user earned their points:

```typescript
const history = await Fuul.getUserPointsMovements({
  user_identifier: address,
  identifier_type: 'evm_address',
});
```

Each movement includes the amount, conversion name, and timestamp. For points, `payout_status` is always `confirmed` since no onchain transaction is needed.

{% hint style="info" %}
Rewards data is updated hourly. Recent conversions and payouts appear within a maximum of one hour.
{% endhint %}

## Next steps

| Feature                            | Guide                                                                                |
| ---------------------------------- | ------------------------------------------------------------------------------------ |
| Add badges for milestones          | [Badges](/incentives-manager/badges.md)                                              |
| Create tiered rewards              | [Tiers & Multipliers](/core-concepts/tiers-and-multipliers.md)                       |
| Target user segments               | [Managing Audiences](/developer-guide/managing-audiences.md)                         |
| Group points by conversion         | [Individual Rewards — Points](/developer-guide/getting-individual-rewards/points.md) |
| Add referrals to earn bonus points | [Tracking Referrals](/developer-guide/tracking-referrals-in-your-app.md)             |


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.fuul.xyz/tutorials/points-program-tutorial.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
