Skip to content

Real-Time Events (SSE) ​

FAST provides a Server-Sent Events stream for real-time notifications. Your frontend receives instant updates when challenges complete, bets are validated, cooldowns trigger, etc.

Authentication ​

EventSource (SSE) cannot send HTTP headers. FAST uses HMAC-signed tokens to authenticate SSE connections without exposing API keys in URLs.

Token endpoint ​

POST /v1/sse/token
X-API-Key: pk_your-widget-key   (or key-your-api-key)
Content-Type: application/json

{ "userId": "player-42" }

Response:

json
{
  "token": "eyJ0aWQiOiJ...",
  "expiresAt": "2026-06-07T15:00:00.000Z",
  "ttl": 3600,
  "userId": "player-42"
}

Connect to SSE ​

GET /v1/events?token=<token>&userId=player-42

No API key in URL. The token is HMAC-signed with a server-side secret and contains:

  • Tenant ID (which operator)
  • User ID (scoped to one player)
  • Expiry timestamp

Token refresh ​

Tokens expire after 1 hour (3600 seconds). The ttl field tells you the lifetime. Reconnect with a fresh token before expiry.

Recommended: refresh at 80% of TTL (every ~48 minutes).

Events ​

The SSE stream carries most of the webhook event types, plus bet.settled. Payloads are smaller than the webhook ones (usually ids and the userId), so treat an event as a signal to refetch progress.

EventWhen
challenge.activatedNew challenge purchased and started
challenge.passedChallenge target reached; user must choose continue or refund
challenge.completedUser continued after passing; Reward Account created
challenge.failedChallenge failed (drawdown, expiry, insufficient active days)
challenge.cancelledUser cancelled the challenge
challenge.stake_refundedUser exited after passing; own stake to be refunded
funded_account.activatedFunded account created after the user continued
funded_account.payoutProfit withdrawn from funded account
funded_account.revokedFunded account closed (drawdown, inactivity, cancellation, admin)
funded_account.stake_refundedOwn stake refunded during the funded phase
bet.validation_resultBet validation response
bet.settledBet settlement processed (SSE only, no webhook)
cooldown.triggeredUser entered cooldown period
cooldown.liftedCooldown ended
reward.grantedReward granted

Engagement modules also stream bonus.activated, bonus.completed, bonus.forfeited, mission.completed, tournament.started, tournament.settled, tournament.user_invited and loyalty.tier_upgraded, and self-exclusion streams user.self_excluded and user.self_exclusion_lifted. reward.applied and the other engagement events are webhook-only.

Implementation examples ​

Browser (vanilla JS) ​

javascript
// 1. Fetch token from your backend (never expose API key in frontend)
const res = await fetch('/api/fast/sse-token', { method: 'POST' });
const { token } = await res.json();

// 2. Connect
const es = new EventSource(
  `https://api.fundedfast.eu/v1/events?token=${token}&userId=player-42`
);

es.addEventListener('challenge.completed', (e) => {
  const data = JSON.parse(e.data);
  showNotification('Challenge completed!');
});

es.addEventListener('cooldown.triggered', (e) => {
  // data: { userId, reason } - read cooldownUntil from GET /v1/users/:userId/progress
  disableBetting();
});

Your backend (token proxy) ​

javascript
// Express route that your frontend calls
app.post('/api/fast/sse-token', async (req, res) => {
  const userId = req.session.userId; // from your auth
  const response = await fetch('https://api.fundedfast.eu/v1/sse/token', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'X-API-Key': process.env.FAST_WIDGET_KEY, // pk_...
    },
    body: JSON.stringify({ userId }),
  });
  const data = await response.json();
  res.json(data);
});

With the FAST Widget ​

The widget handles SSE automatically. No extra code needed:

html
<!-- Optional, recommended: opens the API connection while the script loads. -->
<link rel="preconnect" href="https://api.fundedfast.eu" crossorigin>
<script
  src="https://cdn.fundedfast.eu/fast-widget.iife.js"
  data-fast-widget
  data-api-key="pk_your-widget-key"
  data-user-id="player-42"
  data-api-base="https://api.fundedfast.eu/v1"
></script>

For maximum security, pre-generate the token server-side and mount programmatically instead of via data attributes (window.FastWidget.mount() returns an instance with update/destroy/open):

javascript
const widget = FastWidget.mount({
  apiKey: 'pk_your-widget-key',
  userId: 'player-42',
  apiBase: 'https://api.fundedfast.eu/v1',
  userToken: tokenFromYourBackend, // pre-generated; data-user-token in HTML form
});

// Later, when your backend hands you a refreshed token (e.g. onTokenExpired):
widget.update({ userToken: refreshedToken });

Keep-alive ​

The server sends a comment line (: keepalive) every 30 seconds to prevent connection timeouts.

Error handling ​

If the connection drops, EventSource auto-reconnects. On token expiry (401 response), fetch a new token and create a new EventSource instance.

BLACKLINE CONSULTING d.o.o.