Esta documentación describe todos los endpoints disponibles en la API REST de GameWasters, incluyendo schemas de datos, flujos de autenticación y manejo de errores.
- Autenticación
- Endpoints de Usuario
- Endpoints de Ofertas
- Endpoints de Recomendaciones
- Schemas y Tipos
- Manejo de Errores
La aplicación utiliza Steam OpenID para autenticación. El flujo completo es:
- Obtener URL de Autenticación
- Redirección a Steam
- Callback de Autenticación
- Generación de JWT Token
Genera la URL de autenticación de Steam OpenID.
Query Parameters:
- Ninguno
Response:
{
"url": "https://steamcommunity.com/openid/login?openid.mode=checkid_setup&openid.ns=http://specs.openid.net/auth/2.0&..."
}Status Codes:
200 OK: URL generada exitosamente
Endpoint de callback para la autenticación de Steam.
Query Parameters:
openid.claimed_id(string): URL del perfil de Steam del usuarioopenid.identity(string): URL de identidad OpenIDopenid.return_to(string): URL de retornoopenid.response_nonce(string): Nonce de respuestaopenid.signed(string): Parámetros firmadosopenid.sig(string): Firma digital
Response:
<!DOCTYPE html>
<html>
<head><title>Authentication Result</title></head>
<body>
<script>
window.opener.postMessage({
type: 'STEAM_AUTH_SUCCESS',
steamId: '76561198000000000',
steamName: 'Username',
steamAvatar: 'https://avatars.steamstatic.com/...',
token: 'jwt_token_here'
}, 'http://localhost:3000');
window.close();
</script>
</body>
</html>Status Codes:
200 OK: Autenticación exitosa400 Bad Request: Parámetros inválidos500 Internal Server Error: Error del servidor
Obtiene el perfil completo del usuario con estadísticas detalladas.
Headers:
Authorization: Bearer <jwt_token>(opcional, se puede usar steamId en query)
Query Parameters:
steamId(string, opcional): Steam ID del usuario como fallback
Response:
{
"success": true,
"data": {
"steamId": "76561198000000000",
"steamName": "Username",
"steamAvatar": "https://avatars.steamstatic.com/...",
"summary": {
"totalPlaytimeHours": 1250.5,
"totalGames": 150,
"gamesPlayed": 85,
"gamesNotPlayed": 65,
"topGame": {
"name": "Counter-Strike 2",
"hours": 450.2
},
"estimatedInventoryValue": 250.75,
"playerScore": 78.5,
"rank": "Dedicated Gamer"
},
"achievements": {
"totalUnlocked": 1250,
"totalAchievements": 3000,
"avgCompletion": 41.67,
"perfectGames": 12,
"topGames": [
{
"appid": 730,
"gameName": "Counter-Strike 2",
"totalAchievements": 150,
"unlockedAchievements": 120,
"completionPercent": 80.0
}
]
},
"recentGames": [
{
"appid": 730,
"name": "Counter-Strike 2",
"playtime_forever": 450.2,
"playtime_2weeks": 25.5,
"img_icon_url": "icon_hash",
"img_logo_url": "logo_hash"
}
]
}
}Status Codes:
200 OK: Perfil obtenido exitosamente401 Unauthorized: Usuario no autenticado404 Not Found: Usuario no encontrado500 Internal Server Error: Error del servidor
Obtiene los géneros de juego preferidos del usuario basados en tiempo de juego.
Headers:
Authorization: Bearer <jwt_token>(opcional)
Response:
{
"success": true,
"data": [
{
"name": "Action",
"playtime": 450.5,
"gamesCount": 25,
"percentage": 35.2
},
{
"name": "RPG",
"playtime": 320.8,
"gamesCount": 18,
"percentage": 25.1
},
{
"name": "Strategy",
"playtime": 200.3,
"gamesCount": 12,
"percentage": 15.6
}
]
}Status Codes:
200 OK: Géneros obtenidos exitosamente401 Unauthorized: Usuario no autenticado500 Internal Server Error: Error del servidor
Obtiene ofertas de juegos personalizadas basadas en los géneros preferidos del usuario.
Headers:
Authorization: Bearer <jwt_token>(opcional)
Query Parameters:
steamId(string, opcional): Steam ID para personalización
Response:
{
"success": true,
"data": [
{
"steamId": "76561198000000000",
"title": "Cyberpunk 2077",
"currentPrice": 29.99,
"discount": 75,
"image": "https://cdn.akamai.steamstatic.com/...",
"originalPrice": 119.99,
"savings": 90.00,
"genres": ["RPG", "Action"],
"releaseDate": "2020-12-10",
"metacriticScore": 86
}
]
}Status Codes:
200 OK: Ofertas obtenidas exitosamente401 Unauthorized: Usuario no autenticado500 Internal Server Error: Error del servidor
Obtiene ofertas con precios históricos más bajos.
Headers:
Authorization: Bearer <jwt_token>(opcional)
Response:
{
"success": true,
"data": [
{
"steamId": "76561198000000000",
"title": "The Witcher 3: Wild Hunt",
"currentPrice": 4.99,
"discount": 90,
"image": "https://cdn.akamai.steamstatic.com/...",
"historicalLow": 2.99,
"historicalLowDate": "2021-01-15",
"currentVsHistorical": 66.7,
"genres": ["RPG"],
"releaseDate": "2016-05-19"
}
]
}Status Codes:
200 OK: Ofertas históricas obtenidas exitosamente401 Unauthorized: Usuario no autenticado500 Internal Server Error: Error del servidor
Obtiene recomendaciones de juegos populares basadas en los géneros preferidos del usuario.
Headers:
Authorization: Bearer <jwt_token>(opcional)
Response:
{
"success": true,
"data": [
{
"appId": 271590,
"title": "Grand Theft Auto V",
"score": 92.5,
"gameGenres": ["Action", "Adventure"],
"concurrentPlayers": 150000,
"price": 29.99,
"discount": 50,
"releaseDate": "2015-04-14",
"metacriticScore": 96,
"recommendationReason": "Basado en tu preferencia por juegos de Action"
}
]
}Status Codes:
200 OK: Recomendaciones obtenidas exitosamente401 Unauthorized: Usuario no autenticado500 Internal Server Error: Error del servidor
interface UserGenreStats {
name: string; // Nombre del género
playtime: number; // Tiempo de juego en horas
gamesCount: number; // Cantidad de juegos
percentage: number; // Porcentaje del tiempo total
}interface Deal {
steamId: string; // Steam ID del usuario
title: string; // Título del juego
currentPrice: number; // Precio actual
discount: number; // Descuento porcentual
image: string; // URL de la imagen
originalPrice?: number; // Precio original
savings?: number; // Ahorro total
genres?: string[]; // Géneros del juego
releaseDate?: string; // Fecha de lanzamiento
metacriticScore?: number; // Puntuación Metacritic
}interface TopSteamRecommendation {
appId: number; // ID de la aplicación
title: string; // Título del juego
score: number; // Puntuación de recomendación
gameGenres: string[]; // Géneros del juego
concurrentPlayers: number | null; // Jugadores concurrentes
price?: number; // Precio actual
discount?: number; // Descuento
releaseDate?: string; // Fecha de lanzamiento
metacriticScore?: number; // Puntuación Metacritic
recommendationReason?: string; // Razón de recomendación
}interface PlayerProfile {
steamId: string;
steamName: string;
steamAvatar: string;
summary: {
totalPlaytimeHours: number;
totalGames: number;
gamesPlayed: number;
gamesNotPlayed: number;
topGame: { name: string; hours: number } | null;
estimatedInventoryValue: number;
playerScore: number;
rank: string;
};
achievements: {
totalUnlocked: number;
totalAchievements: number;
avgCompletion: number;
perfectGames: number;
topGames: Array<{
appid: number;
gameName: string;
totalAchievements: number;
unlockedAchievements: number;
completionPercent: number;
}>;
};
recentGames: Array<{
appid: number;
name: string;
playtime_forever: number;
playtime_2weeks: number;
img_icon_url: string;
img_logo_url: string;
}>;
}{
"success": false,
"error": "Mensaje descriptivo del error",
"code": "ERROR_CODE",
"details": {} // Información adicional opcional
}| Código | Descripción |
|---|---|
UNAUTHORIZED |
Usuario no autenticado |
INVALID_STEAM_ID |
Steam ID inválido |
STEAM_API_ERROR |
Error en la API de Steam |
DATABASE_ERROR |
Error en la base de datos |
VALIDATION_ERROR |
Error de validación de datos |
RATE_LIMIT_EXCEEDED |
Límite de tasa excedido |
INTERNAL_ERROR |
Error interno del servidor |
- Steam API: 100,000 llamadas por día
- Endpoints de usuario: 1000 llamadas por hora por usuario
- Endpoints de ofertas: 500 llamadas por hora por usuario
- Recomendaciones: 200 llamadas por hora por usuario
- Todos los Steam IDs son cifrados usando AES-256 antes de almacenar
- Los tokens JWT tienen una expiración de 24 horas
- Las respuestas de Steam API son validadas y sanitizadas
- Se implementan políticas CORS estrictas
- Los datos sensibles nunca son expuestos en logs o respuestas
// 1. Obtener URL de autenticación
const authResponse = await fetch('/api/auth/steam/url');
const { url } = await authResponse.json();
// 2. Redirigir a Steam
window.location.href = url;
// 3. Después del callback, el token JWT se recibe via postMessage
window.addEventListener('message', (event) => {
if (event.data.type === 'STEAM_AUTH_SUCCESS') {
const { token } = event.data;
localStorage.setItem('jwt_token', token);
}
});
// 4. Usar el token para llamadas autenticadas
const profileResponse = await fetch('/api/user/profile', {
headers: {
'Authorization': `Bearer ${token}`
}
});const token = localStorage.getItem('jwt_token');
const recommendationsResponse = await fetch('/api/recommendations/top-steam', {
headers: {
'Authorization': `Bearer ${token}`
}
});
const { success, data } = await recommendationsResponse.json();
if (success) {
console.log('Recomendaciones:', data);
}- La API soporta tanto SQLite como almacenamiento en memoria
- En Vercel, se usa almacenamiento en memoria por limitaciones del filesystem
- Las variables de entorno deben configurarse antes del despliegue
- La API automáticamente detecta y fallback a memoria si SQLite no está disponible