Endpoints - Challenges
Les challenges (défis / quiz) ont une API moderne paginée et des chemins legacy encore utilisés par certaines apps.
GET /public/challenges?cityId= et POST /public/challenges/:id/complete — SDK client.public.challenges.*
API actuelle
| Méthode | Path | SDK |
|---|---|---|
| GET | /public/challenges?cityId=&page=&pageSize= | list(cityId?, params?) |
| GET | /public/challenges/:id | getById(id) |
| GET | /public/challenges/:id/series | getSeries(id) |
| POST | /public/challenges/:id/complete | complete(id, { deviceId, score }) |
| GET | /public/challenges/progress/:deviceId | getProgress(deviceId) |
Body complete : { "deviceId": "…", "score": 85 }.
Séries / questions
GET /public/series/:id
GET /public/series/:id/questions
La série n’est renvoyée que si le challenge parent est public et actif. Pas de wrapper SDK sur /public/series : passer par getSeries puis ces URLs, ou le détail getById.
Legacy (tableau non paginé)
Les routes ci-dessous restent valides mais GET /public/challenges/:cityId est ambigu avec GET /public/challenges/:id. Pour une ville, utilisez ?cityId= ou GET /public/cities/:id/challenges.
Liste des challenges d'une ville (legacy)
Récupère tous les challenges actifs et disponibles pour une ville spécifique.
Requête
GET /public/challenges/:cityId
Paramètres
cityId(string, requis) : Identifiant unique de la ville (UUID)
Réponse
[
{
"id": "challenge-uuid",
"name": "Apprenti Trieur",
"description": "Apprenez les bases du tri des déchets",
"enabled": true,
"startDate": "2024-01-01T00:00:00.000Z",
"endDate": null,
"order": 1,
"requiredChallengeId": null,
"requiredChallenge": null,
"series": [
{
"id": "serie-uuid",
"name": "Série 1 - Les bases",
"description": "Première série de questions sur les bases du tri",
"order": 1,
"quizQuestions": [
{
"id": "question-uuid-1",
"material": "Bouteille en plastique",
"question": "Dans quel bac dois-je jeter cette bouteille ?",
"correctWasteTypeId": "waste-type-uuid",
"order": 1
},
{
"id": "question-uuid-2",
"material": "Journal",
"question": "Où dois-je jeter ce journal ?",
"correctWasteTypeId": "waste-type-uuid-2",
"order": 2
}
]
},
{
"id": "serie-uuid-2",
"name": "Série 2 - Le recyclage",
"description": "Questions sur le recyclage",
"order": 2,
"quizQuestions": [
{
"id": "question-uuid-3",
"material": "Brique de lait",
"question": "Cette brique de lait est-elle recyclable ?",
"correctWasteTypeId": "waste-type-uuid",
"order": 1
}
]
}
],
"badge": {
"id": "badge-uuid",
"name": "Apprenti Trieur",
"description": "Vous avez complété votre premier challenge",
"icon": "star",
"imageUrl": "https://example.com/badge.png"
}
}
]
Exemple d'utilisation
const cityId = 'city-uuid';
const response = await fetch(`https://api.wast-o.com/public/challenges/${cityId}`);
const challenges = await response.json();
// Filtrer les challenges disponibles
const now = new Date();
const availableChallenges = challenges.filter(challenge => {
if (challenge.startDate && new Date(challenge.startDate) > now) return false;
if (challenge.endDate && new Date(challenge.endDate) < now) return false;
return challenge.enabled;
});
console.log(`Challenges disponibles: ${availableChallenges.length}`);
Compléter un challenge
Enregistre la complétion d'un challenge par un utilisateur avec son score.
Requête
POST /public/challenges/complete
Corps de la requête
{
"deviceId": "device-uuid",
"challengeId": "challenge-uuid",
"score": 85
}
Paramètres
deviceId(string, requis) : Identifiant unique de l'appareil/utilisateurchallengeId(string, requis) : Identifiant du challenge complétéscore(number, requis) : Score obtenu (généralement entre 0 et 100)
Réponse
{
"id": "progress-uuid",
"deviceId": "device-uuid",
"challengeId": "challenge-uuid",
"score": 85,
"completedAt": "2024-01-15T10:30:00.000Z",
"challenge": {
"id": "challenge-uuid",
"name": "Apprenti Trieur",
"description": "Apprenez les bases du tri",
"badge": {
"id": "badge-uuid",
"name": "Apprenti Trieur",
"description": "Vous avez complété votre premier challenge",
"icon": "star",
"imageUrl": "https://example.com/badge.png"
}
}
}
Exemple d'utilisation
const deviceId = 'device-uuid';
const challengeId = 'challenge-uuid';
const score = 85;
const response = await fetch('https://api.wast-o.com/public/challenges/complete', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
deviceId,
challengeId,
score,
}),
});
const result = await response.json();
console.log(`Challenge complété ! Badge obtenu: ${result.challenge.badge.name}`);
Codes d'erreur
400 Bad Request: Paramètres invalides404 Not Found: Le challenge n'existe pas ou n'est pas disponible400 Bad Request: Le challenge n'a pas encore commencé ou est terminé
Progression d'un utilisateur
Récupère la progression de tous les challenges complétés par un utilisateur.
Requête
GET /public/challenges/progress/:deviceId
Paramètres
deviceId(string, requis) : Identifiant unique de l'appareil/utilisateur
Réponse
[
{
"challengeId": "challenge-uuid-1",
"challengeName": "Apprenti Trieur",
"score": 85,
"completedAt": "2024-01-15T10:30:00.000Z",
"badge": {
"id": "badge-uuid",
"name": "Apprenti Trieur",
"description": "Vous avez complété votre premier challenge",
"icon": "star",
"imageUrl": "https://example.com/badge.png"
}
},
{
"challengeId": "challenge-uuid-2",
"challengeName": "Expert du Tri",
"score": 95,
"completedAt": "2024-01-20T14:15:00.000Z",
"badge": {
"id": "badge-uuid-2",
"name": "Expert du Tri",
"description": "Vous maîtrisez le tri des déchets",
"icon": "trophy",
"imageUrl": "https://example.com/badge-expert.png"
}
}
]
Exemple d'utilisation
const deviceId = 'device-uuid';
const response = await fetch(`https://api.wast-o.com/public/challenges/progress/${deviceId}`);
const progress = await response.json();
console.log(`Challenges complétés: ${progress.length}`);
progress.forEach(p => {
console.log(`${p.challengeName}: ${p.score}% - Badge: ${p.badge.name}`);
});
Génération d'un deviceId
Pour suivre la progression d'un utilisateur, vous devez générer et stocker un deviceId unique. Voici un exemple d'implémentation :
function getOrCreateDeviceId() {
const STORAGE_KEY = 'wasto_device_id';
let deviceId = localStorage.getItem(STORAGE_KEY);
if (!deviceId) {
// Générer un UUID v4
deviceId = 'web_' + crypto.randomUUID();
localStorage.setItem(STORAGE_KEY, deviceId);
}
return deviceId;
}
// Utilisation
const deviceId = getOrCreateDeviceId();
Schémas de données
Challenge
interface Challenge {
id: string;
name: string;
description?: string;
enabled: boolean;
startDate?: string;
endDate?: string;
order: number;
requiredChallengeId?: string;
requiredChallenge?: {
id: string;
name: string;
};
series: Serie[];
badge?: Badge;
}
interface Serie {
id: string;
name: string;
description?: string;
order: number;
quizQuestions: QuizQuestion[];
}
interface QuizQuestion {
id: string;
material: string;
question: string;
correctWasteTypeId: string;
order: number;
}
interface Badge {
id: string;
name: string;
description?: string;
icon?: string;
imageUrl?: string;
}
UserProgress
interface UserProgress {
challengeId: string;
challengeName: string;
score: number;
completedAt: string;
badge?: Badge;
}