Fetch Users Data
Fetches user information and flight history for multiple users in a single request.
Content-Type
string
default:"application/json"
Must be application/json
Body Parameters
Accepts either format:
Format 1: Object with userIds array
{
"userIds": ["123456789", "987654321"]
}
Format 2: Array of user IDs
["123456789", "987654321"]
Array of ROBLOX user IDs to fetch data for
Response
Array of user data objects, one for each requested user ID
User object (null if user doesn’t exist)
When the user was created
When the user was last updated
Array of flight history objects for this user
Miles earned from this flight
Example Request
curl -X POST https://api.skyteam.dev/users/fetchUsersData \
-H "x-api-key: your_api_key_here" \
-H "Content-Type: application/json" \
-d '{
"userIds": ["123456789", "987654321"]
}'
Example Response
{
"data": [
{
"userId": "123456789",
"user": {
"userId": "123456789",
"username": "pilot123",
"displayName": "Captain John",
"miles": 5000,
"avatarUrl": "https://tr.rbxcdn.com/...",
"createdAt": "2024-01-10T08:00:00.000Z",
"updatedAt": "2024-03-15T10:30:00.000Z"
},
"flights": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"code": "ST123",
"gameId": "1234567890",
"aircraft": "Boeing 737-800",
"airlineId": "skyteam",
"brandId": "skyteam-main",
"departure": "KJFK",
"arrival": "KLAX",
"miles": 500,
"startTime": "2024-03-15T14:00:00.000Z",
"startedAt": "2024-03-15T14:05:00.000Z",
"endTime": "2024-03-15T16:30:00.000Z",
"codeshareAirlineId": null,
"discordEventLink": "https://discord.gg/event/123456"
}
]
},
{
"userId": "987654321",
"user": null,
"flights": []
}
]
}
Error Response
Status: 400 Bad Request
{
"error": "Provide a list of userIds in the request body"
}
Implementation Notes
- Duplicate user IDs are automatically de-duplicated to reduce database queries
- Results are returned in the same order as requested
- Users that don’t exist return
null for the user object with an empty flights array
- All user IDs are trimmed and filtered to remove empty strings
Buy Product
Purchases a miles product for a user, deducting the miles cost from their account.
Content-Type
string
default:"application/json"
Must be application/json
Path Parameters
The ROBLOX user ID of the user purchasing the product
Body Parameters
The ID of the product to purchase
Response
Updated user object with new miles balance
The purchased product object
Example Request
curl -X POST https://api.skyteam.dev/user/123456789/buyProduct \
-H "x-api-key: your_api_key_here" \
-H "Content-Type: application/json" \
-d '{
"productId": "a1b2c3"
}'
Example Response
{
"ok": true,
"user": {
"userId": "123456789",
"username": "pilot123",
"displayName": "Captain John",
"miles": 4500,
"avatarUrl": "https://tr.rbxcdn.com/...",
"createdAt": "2024-01-10T08:00:00.000Z",
"updatedAt": "2024-03-15T10:30:00.000Z"
},
"product": {
"productId": "a1b2c3",
"airlineId": "skyteam",
"name": "Priority Boarding",
"description": "Board the aircraft before other passengers",
"priceMiles": 500,
"active": true,
"createdAt": "2024-01-15T10:30:00.000Z"
}
}
Error Responses
Missing Product ID
Status: 400 Bad Request
{
"error": "Missing productId in body"
}
User Not Found
Status: 404 Not Found
{
"error": "User not found"
}
Product Not Found
Status: 404 Not Found
{
"error": "Product not found"
}
Insufficient Miles
Status: 400 Bad Request
{
"error": "Insufficient miles"
}
Transaction Behavior
- The purchase is atomic - either both the miles deduction and transaction record succeed, or neither happens
- A miles transaction record is created with type
spend and source purchase
- Only active products can be purchased
- The product must belong to the authenticated airline
Implementation
Location: apps/api/src/routes/users.ts:74
router.post("/user/:id/buyProduct", async (req, res, next) => {
const { id: userId } = req.params;
const { productId } = req.body as { productId?: string };
const airline = res.locals.airline as { airlineId: string };
const [user, products] = await Promise.all([
fetchUser(userId),
fetchMilesProducts(airline.airlineId),
]);
if (!user) return res.status(404).json({ error: "User not found" });
const product = products.find(
(p) => p.productId === productId && p.active !== false,
);
if (!product) return res.status(404).json({ error: "Product not found" });
const updated = await spendMiles(
userId,
product.priceMiles,
`Purchase: ${product.name}`,
);
res.json({ ok: true, user: updated, product });
});