04 — API: Auth & User Management
Endpoint untuk registrasi, login, profil, dan preferensi user.
Auth Endpoints
POST /auth/sign-up/email
Registrasi user baru dengan email dan password.
Access: Public
// Request Body
{
"email": "user@example.com",
"password": "minimalDelapanKarakter",
"name": "Budi Santoso",
"guestId": "guest_abc123" // Opsional: link data assessment guest
}
// Response 201
{
"success": true,
"data": {
"user": {
"id": "usr_V1StGXR8_Z5j",
"email": "user@example.com",
"name": "Budi Santoso",
"tier": "free",
"onboardingCompleted": false,
"createdAt": "2026-09-20T08:00:00Z"
},
"session": {
"token": "ses_xxxxx",
"expiresAt": "2026-09-27T08:00:00Z"
}
}
}
// Response 409 (Email sudah terdaftar)
{
"success": false,
"error": {
"code": "CONFLICT",
"message": "Email sudah terdaftar"
}
}
POST /auth/sign-in/email
Login dengan email dan password.
Access: Public
// Request Body
{
"email": "user@example.com",
"password": "password123"
}
// Response 200
{
"success": true,
"data": {
"user": {
"id": "usr_V1StGXR8_Z5j",
"email": "user@example.com",
"name": "Budi Santoso",
"tier": "member",
"image": "https://r2.eljoy.id/avatars/usr_V1StGXR8_Z5j.jpg",
"onboardingCompleted": true
},
"session": {
"token": "ses_xxxxx",
"expiresAt": "2026-09-27T08:00:00Z"
}
}
}
POST /auth/sign-in/social
Login/register via OAuth (Google atau Apple).
Access: Public
// Request Body
{
"provider": "google", // "google" | "apple"
"idToken": "eyJhbGciOiJ...", // OAuth ID token dari provider
"guestId": "guest_abc123" // Opsional: link guest data
}
// Response 200 (User sudah ada → login)
// Response 201 (User baru → register + login)
{
"success": true,
"data": {
"user": { ... },
"session": { ... },
"isNewUser": true
}
}
POST /auth/sign-out
Logout dan hapus session.
Access: Authenticated
// Response 200
{
"success": true,
"data": {
"message": "Berhasil logout"
}
}
GET /auth/session
Cek status session saat ini (untuk auto-login di frontend).
Access: Public (return null kalau belum login)
// Response 200 (Sudah login)
{
"success": true,
"data": {
"user": {
"id": "usr_V1StGXR8_Z5j",
"email": "user@example.com",
"name": "Budi Santoso",
"tier": "member",
"image": null,
"onboardingCompleted": true
}
}
}
// Response 200 (Belum login)
{
"success": true,
"data": null
}
POST /auth/forgot-password
Kirim email reset password.
Access: Public
// Request Body
{
"email": "user@example.com"
}
// Response 200 (Selalu success, untuk keamanan)
{
"success": true,
"data": {
"message": "Jika email terdaftar, link reset password telah dikirim"
}
}
POST /auth/reset-password
Reset password dengan token dari email.
Access: Public
// Request Body
{
"token": "reset_token_xxx",
"newPassword": "passwordBaru123"
}
// Response 200
{
"success": true,
"data": {
"message": "Password berhasil direset"
}
}
User Endpoints
GET /users/me
Ambil profil user yang sedang login.
Access: Authenticated
// Response 200
{
"success": true,
"data": {
"id": "usr_V1StGXR8_Z5j",
"email": "user@example.com",
"name": "Budi Santoso",
"image": "https://r2.eljoy.id/avatars/usr_V1StGXR8_Z5j.jpg",
"tier": "member",
"nativeLanguage": "id",
"timezone": "Asia/Jakarta",
"onboardingCompleted": true,
"createdAt": "2026-09-01T08:00:00Z",
"learnerProfile": {
"cefrLevel": "b1",
"currentStreak": 7,
"longestStreak": 14,
"totalXp": 2450,
"currentLevel": 5,
"totalSessions": 23,
"totalSpeakingMinutes": 187
},
"subscription": {
"planName": "Monthly",
"status": "active",
"expiresAt": "2026-10-20T08:00:00Z"
}
}
}
PATCH /users/me
Update profil user.
Access: Authenticated
// Request Body (partial update)
{
"name": "Budi Santoso Jr.",
"nativeLanguage": "id",
"timezone": "Asia/Jakarta"
}
// Response 200
{
"success": true,
"data": {
"id": "usr_V1StGXR8_Z5j",
"name": "Budi Santoso Jr.",
"nativeLanguage": "id",
"timezone": "Asia/Jakarta"
}
}
PUT /users/me/avatar
Upload foto profil.
Access: Authenticated
PUT /api/v1/users/me/avatar
Content-Type: multipart/form-data
avatar: <file> (max 2MB, jpg/png/webp)
// Response 200
{
"success": true,
"data": {
"image": "https://r2.eljoy.id/avatars/usr_V1StGXR8_Z5j.jpg"
}
}
GET /users/me/preferences
Ambil preferensi user.
Access: Authenticated
// Response 200
{
"success": true,
"data": {
"theme": "dark",
"uiLanguage": "id",
"ttsSpeed": 1.0,
"ttsVoice": "alloy",
"muteSfx": false,
"autoPlayTts": true,
"dailyGoalMinutes": 15,
"reminderTime": "19:00",
"reminderEnabled": true
}
}
PATCH /users/me/preferences
Update preferensi user.
Access: Authenticated
// Request Body (partial update)
{
"theme": "light",
"ttsSpeed": 1.2,
"dailyGoalMinutes": 30
}
// Response 200
{
"success": true,
"data": { ... } // Updated preferences
}
DELETE /users/me
Hapus akun (soft delete).
Access: Authenticated
// Request Body
{
"confirmation": "HAPUS AKUN SAYA"
}
// Response 200
{
"success": true,
"data": {
"message": "Akun berhasil dihapus. Data akan dihapus permanen dalam 30 hari."
}
}