Complete REST API documentation for the flashcard backend.
http://localhost:3001/api
Most endpoints require a JWT token. Include it in the Authorization header:
Authorization: Bearer <your-jwt-token>
POST /auth/registerBody:
{
"email": "user@example.com",
"username": "john_doe",
"password": "secure_password123"
}Response (201):
{
"user": {
"id": "uuid",
"email": "user@example.com",
"username": "john_doe",
"createdAt": "2024-01-15T10:00:00.000Z"
},
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}POST /auth/loginBody:
{
"email": "user@example.com",
"password": "secure_password123"
}Response (200):
{
"user": {
"id": "uuid",
"email": "user@example.com",
"username": "john_doe"
},
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}GET /auth/meHeaders:
Authorization: Bearer <token>
Response (200):
{
"id": "uuid",
"email": "user@example.com",
"username": "john_doe",
"createdAt": "2024-01-15T10:00:00.000Z"
}GET /decksHeaders:
Authorization: Bearer <token>
Response (200):
[
{
"id": "deck-uuid-1",
"name": "Spanish Vocabulary",
"description": "Common Spanish words",
"createdAt": "2024-01-15T10:00:00.000Z",
"updatedAt": "2024-01-15T10:00:00.000Z",
"userId": "user-uuid",
"_count": {
"cards": 25
}
}
]GET /decks/:deckIdHeaders:
Authorization: Bearer <token>
Response (200):
{
"id": "deck-uuid",
"name": "Spanish Vocabulary",
"description": "Common Spanish words",
"createdAt": "2024-01-15T10:00:00.000Z",
"updatedAt": "2024-01-15T10:00:00.000Z",
"userId": "user-uuid",
"_count": {
"cards": 25
}
}POST /decksHeaders:
Authorization: Bearer <token>
Content-Type: application/json
Body:
{
"name": "Spanish Vocabulary",
"description": "Common Spanish words"
}Response (201):
{
"id": "deck-uuid",
"name": "Spanish Vocabulary",
"description": "Common Spanish words",
"createdAt": "2024-01-15T10:00:00.000Z",
"updatedAt": "2024-01-15T10:00:00.000Z",
"userId": "user-uuid"
}PATCH /decks/:deckIdHeaders:
Authorization: Bearer <token>
Content-Type: application/json
Body:
{
"name": "Updated Deck Name",
"description": "Updated description"
}Response (200):
{
"id": "deck-uuid",
"name": "Updated Deck Name",
"description": "Updated description",
"createdAt": "2024-01-15T10:00:00.000Z",
"updatedAt": "2024-01-15T11:00:00.000Z",
"userId": "user-uuid"
}DELETE /decks/:deckIdHeaders:
Authorization: Bearer <token>
Response (204):
No content
GET /cards/deck/:deckIdHeaders:
Authorization: Bearer <token>
Response (200):
[
{
"id": "card-uuid-1",
"front": "Hola",
"back": "Hello",
"easeFactor": 2.5,
"interval": 0,
"repetitions": 0,
"dueDate": "2024-01-15T10:00:00.000Z",
"createdAt": "2024-01-15T10:00:00.000Z",
"updatedAt": "2024-01-15T10:00:00.000Z",
"deckId": "deck-uuid"
}
]GET /cards/:cardIdHeaders:
Authorization: Bearer <token>
Response (200):
{
"id": "card-uuid",
"front": "Hola",
"back": "Hello",
"easeFactor": 2.5,
"interval": 0,
"repetitions": 0,
"dueDate": "2024-01-15T10:00:00.000Z",
"createdAt": "2024-01-15T10:00:00.000Z",
"updatedAt": "2024-01-15T10:00:00.000Z",
"deckId": "deck-uuid",
"deck": {
"id": "deck-uuid",
"name": "Spanish Vocabulary",
"userId": "user-uuid"
}
}POST /cardsHeaders:
Authorization: Bearer <token>
Content-Type: application/json
Body:
{
"deckId": "deck-uuid",
"front": "Hola",
"back": "Hello"
}Response (201):
{
"id": "card-uuid",
"front": "Hola",
"back": "Hello",
"easeFactor": 2.5,
"interval": 0,
"repetitions": 0,
"dueDate": "2024-01-15T10:00:00.000Z",
"createdAt": "2024-01-15T10:00:00.000Z",
"updatedAt": "2024-01-15T10:00:00.000Z",
"deckId": "deck-uuid"
}PATCH /cards/:cardIdHeaders:
Authorization: Bearer <token>
Content-Type: application/json
Body:
{
"front": "¡Hola!",
"back": "Hello!"
}Response (200):
{
"id": "card-uuid",
"front": "¡Hola!",
"back": "Hello!",
"easeFactor": 2.5,
"interval": 0,
"repetitions": 0,
"dueDate": "2024-01-15T10:00:00.000Z",
"createdAt": "2024-01-15T10:00:00.000Z",
"updatedAt": "2024-01-15T11:00:00.000Z",
"deckId": "deck-uuid"
}DELETE /cards/:cardIdHeaders:
Authorization: Bearer <token>
Response (204):
No content
GET /study/deck/:deckId/dueHeaders:
Authorization: Bearer <token>
Response (200):
{
"card": {
"id": "card-uuid",
"front": "Hola",
"back": "Hello",
"easeFactor": 2.5,
"interval": 0,
"repetitions": 0,
"dueDate": "2024-01-15T10:00:00.000Z",
"createdAt": "2024-01-15T10:00:00.000Z",
"updatedAt": "2024-01-15T10:00:00.000Z",
"deckId": "deck-uuid"
}
}Response when no cards due:
{
"card": null,
"message": "No cards due for review"
}GET /study/dueHeaders:
Authorization: Bearer <token>
Response (200):
{
"count": 12,
"cards": [
{
"id": "card-uuid-1",
"front": "Hola",
"back": "Hello",
"easeFactor": 2.5,
"interval": 0,
"repetitions": 0,
"dueDate": "2024-01-15T10:00:00.000Z",
"deckId": "deck-uuid-1",
"deck": {
"id": "deck-uuid-1",
"name": "Spanish Vocabulary"
}
}
]
}POST /study/answerHeaders:
Authorization: Bearer <token>
Content-Type: application/json
Body:
{
"cardId": "card-uuid",
"quality": 4
}Quality Scale (SM-2 Algorithm):
5- Perfect response4- Correct response after hesitation3- Correct response with difficulty2- Incorrect; correct answer seemed easy to recall1- Incorrect; correct answer remembered0- Complete blackout
Response (200):
{
"card": {
"id": "card-uuid",
"front": "Hola",
"back": "Hello",
"easeFactor": 2.6,
"interval": 1,
"repetitions": 1,
"dueDate": "2024-01-16T10:00:00.000Z",
"createdAt": "2024-01-15T10:00:00.000Z",
"updatedAt": "2024-01-15T10:30:00.000Z",
"deckId": "deck-uuid"
},
"nextReview": "2024-01-16T10:00:00.000Z"
}GET /study/statsHeaders:
Authorization: Bearer <token>
Response (200):
{
"totalCards": 150,
"dueCards": 12,
"reviewsToday": 25,
"totalDecks": 5
}{
"error": [
{
"code": "invalid_type",
"expected": "string",
"received": "undefined",
"path": ["email"],
"message": "Required"
}
]
}{
"error": "Invalid or expired token"
}{
"error": "Deck not found"
}{
"error": "Internal server error"
}# 1. Register
TOKEN=$(curl -s -X POST http://localhost:3001/api/auth/register \
-H "Content-Type: application/json" \
-d '{"email":"test@example.com","username":"test","password":"password123"}' \
| jq -r '.token')
# 2. Create deck
DECK_ID=$(curl -s -X POST http://localhost:3001/api/decks \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"name":"Spanish","description":"Spanish words"}' \
| jq -r '.id')
# 3. Create card
CARD_ID=$(curl -s -X POST http://localhost:3001/api/cards \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d "{\"deckId\":\"$DECK_ID\",\"front\":\"Hola\",\"back\":\"Hello\"}" \
| jq -r '.id')
# 4. Get due cards
curl -s -X GET http://localhost:3001/api/study/due \
-H "Authorization: Bearer $TOKEN" | jq '.'
# 5. Answer card (quality 4 = good)
curl -s -X POST http://localhost:3001/api/study/answer \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d "{\"cardId\":\"$CARD_ID\",\"quality\":4}" | jq '.'Currently no rate limiting is implemented. In production, consider adding:
express-rate-limitfor API endpoints- Per-user limits on deck/card creation
CORS is currently open (*). Update in production:
// src/index.ts
app.use(cors({
origin: 'https://your-frontend-domain.com',
credentials: true
}));