Appearance
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-42No 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.
| Event | When |
|---|---|
challenge.activated | New challenge purchased and started |
challenge.passed | Challenge target reached; user must choose continue or refund |
challenge.completed | User continued after passing; Reward Account created |
challenge.failed | Challenge failed (drawdown, expiry, insufficient active days) |
challenge.cancelled | User cancelled the challenge |
challenge.stake_refunded | User exited after passing; own stake to be refunded |
funded_account.activated | Funded account created after the user continued |
funded_account.payout | Profit withdrawn from funded account |
funded_account.revoked | Funded account closed (drawdown, inactivity, cancellation, admin) |
funded_account.stake_refunded | Own stake refunded during the funded phase |
bet.validation_result | Bet validation response |
bet.settled | Bet settlement processed (SSE only, no webhook) |
cooldown.triggered | User entered cooldown period |
cooldown.lifted | Cooldown ended |
reward.granted | Reward 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.