Skip to main content

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."
}
}