FitMatch
Fitur matching Fumai: temukan partner olahraga, workout buddy, atau koneksi baru. Semua endpoint memerlukan JWT authentication.
Info: FitMatch bersifat opsional. Saat membuat profil FitMatch, data otomatis di-sync dari profil utama user (bio, foto, tinggi, kota, olahraga, ketersediaan).
Profile
GET /fitmatch/profile
Mendapatkan profil FitMatch sendiri.
curl -X GET https://fumai.app/api/mobile/v1/fitmatch/profile \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"const res = await fetch('https://fumai.app/api/mobile/v1/fitmatch/profile', {
headers: { Authorization: `Bearer ${accessToken}` },
})
const data = await res.json()Response 200
{
"success": true,
"data": {
"id": "clx...",
"displayName": "John",
"bio": "Fitness enthusiast",
"birthDate": "1995-06-15",
"gender": "MALE",
"height": 175,
"city": "Denpasar",
"age": 30,
"status": "ACTIVE",
"profileScore": 85,
"photos": [
{ "id": "...", "url": "https://cdn.fumai.app/...", "isMain": true, "sortOrder": 0 }
],
"prompts": [
{ "id": "...", "question": "My go-to workout is...", "answer": "Morning run" }
]
}
}POST /fitmatch/profile
Membuat profil FitMatch. Data yang tidak dikirim akan otomatis di-sync dari profil utama.
Request Body
| Field | Tipe | Wajib | Keterangan |
|---|---|---|---|
displayName | string | Ya | Nama tampilan |
birthDate | string | Ya | Tanggal lahir (ISO date) |
gender | string | Ya | "MALE" atau "FEMALE" |
bio | string | Tidak | Bio khusus FitMatch |
height | number | Tidak | Tinggi dalam cm |
lookingFor | string[] | Tidak | Gender yang dicari (contoh: ["FEMALE"]) |
interestedIn | string[] | Tidak | Dari opsi fitmatch_interest |
ageMin | number | Tidak | Usia minimum filter |
ageMax | number | Tidak | Usia maksimum filter |
maxDistance | number | Tidak | Radius maks dalam km |
fitnessGoals | string[] | Tidak | Contoh: ["MUSCLE_GAIN", "STAY_FIT"] |
prompts | object[] | Tidak | Q&A untuk profil: [{ question, answer }] |
Auto-sync dari Profile
| Field FitMatch | Sumber Profile |
|---|---|
bio | Profile.bio |
height | Profile.height (dalam cm) |
city | Nama kota dari Profile.cityId |
latitude/longitude | Profile.latitude/longitude |
photos | Profile.photos[] → FitMatchPhoto[] |
sports | Profile.favoriteSports[] → SportPreference[] |
curl -X POST https://fumai.app/api/mobile/v1/fitmatch/profile \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"displayName": "John",
"birthDate": "1995-06-15",
"gender": "MALE",
"lookingFor": ["FEMALE"],
"interestedIn": ["workout_buddy", "dating"],
"ageMin": 20,
"ageMax": 30,
"maxDistance": 15
}'const res = await fetch('https://fumai.app/api/mobile/v1/fitmatch/profile', {
method: 'POST',
headers: {
Authorization: `Bearer ${accessToken}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
displayName: 'John',
birthDate: '1995-06-15',
gender: 'MALE',
lookingFor: ['FEMALE'],
interestedIn: ['workout_buddy', 'dating'],
ageMin: 20,
ageMax: 30,
maxDistance: 15,
}),
})PUT /fitmatch/profile
Update profil FitMatch (partial update).
curl -X PUT https://fumai.app/api/mobile/v1/fitmatch/profile \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "bio": "Updated bio", "maxDistance": 20 }'DELETE /fitmatch/profile
Hapus profil FitMatch.
curl -X DELETE https://fumai.app/api/mobile/v1/fitmatch/profile \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"GET /fitmatch/profile/:profileId
Lihat profil FitMatch user lain. Response termasuk compatibility score dan match status.
curl -X GET https://fumai.app/api/mobile/v1/fitmatch/profile/clx... \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"Photos
GET /fitmatch/photos
Mendapatkan daftar foto FitMatch.
curl -X GET https://fumai.app/api/mobile/v1/fitmatch/photos \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"POST /fitmatch/photos
Upload foto FitMatch baru.
Content-Type: multipart/form-data| Field | Tipe | Wajib | Keterangan |
|---|---|---|---|
file | File | Ya | Image file (maks 5MB, JPEG/PNG/WebP) |
Response 200
{
"success": true,
"data": {
"photo": {
"id": "...",
"url": "https://cdn.fumai.app/...",
"isMain": false,
"sortOrder": 2
}
}
}Batasan: Min 2 foto, maks 6 foto.
PUT /fitmatch/photos
Reorder foto atau set foto utama.
{ "photoIds": ["id1", "id2", "id3"] }atau:
{ "mainPhotoId": "id1" }DELETE /fitmatch/photos
Hapus foto.
| Parameter | Tipe | Keterangan |
|---|---|---|
id | string | Photo ID (query parameter) |
curl -X DELETE "https://fumai.app/api/mobile/v1/fitmatch/photos?id=PHOTO_ID" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"Discover & Swipe
GET /fitmatch/discover
Mendapatkan profil untuk di-discover/swipe.
| Parameter | Tipe | Keterangan |
|---|---|---|
limit | number | Jumlah profil (default: 10) |
excludeIds | string | Comma-separated ID yang dikecualikan |
curl -X GET "https://fumai.app/api/mobile/v1/fitmatch/discover?limit=10" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"const res = await fetch('https://fumai.app/api/mobile/v1/fitmatch/discover?limit=10', {
headers: { Authorization: `Bearer ${accessToken}` },
})
const data = await res.json()Response 200
{
"success": true,
"data": {
"profiles": [
{
"id": "...",
"displayName": "Jane",
"age": 25,
"gender": "FEMALE",
"bio": "...",
"photos": [{ "url": "...", "isMain": true }],
"distance": 5.2,
"compatibilityScore": 85,
"fitnessLevel": "INTERMEDIATE",
"fitnessGoals": ["STAY_FIT"]
}
],
"remaining": 8,
"limits": { "dailySwipes": 10, "remaining": 8, "used": 2 }
}
}Daily Limits: Free tier 10 swipe/hari, Plus tier unlimited.
POST /fitmatch/swipe
Swipe pada profil.
Request Body
| Field | Tipe | Wajib | Keterangan |
|---|---|---|---|
targetProfileId | string | Ya | ID profil target |
swipeType | string | Ya | "PASS", "LIKE", atau "WORKOUT_BUDDY" |
| Swipe Type | Keterangan |
|---|---|
PASS | Tidak tertarik |
LIKE | Tertarik (romantis) |
WORKOUT_BUDDY | Tertarik (partner olahraga) |
curl -X POST https://fumai.app/api/mobile/v1/fitmatch/swipe \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "targetProfileId": "clx...", "swipeType": "LIKE" }'const res = await fetch('https://fumai.app/api/mobile/v1/fitmatch/swipe', {
method: 'POST',
headers: {
Authorization: `Bearer ${accessToken}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ targetProfileId: 'clx...', swipeType: 'LIKE' }),
})
const data = await res.json()Response — Match!
{
"success": true,
"data": {
"swipeType": "LIKE",
"isMatch": true,
"match": {
"matchId": "clx...",
"matchType": "LIKE",
"matchedAt": "2026-03-31T...",
"matchedProfile": {
"id": "...",
"displayName": "Jane",
"age": 25,
"photo": "https://..."
}
},
"remaining": 7
}
}Matches & Chat
GET /fitmatch/matches
Mendapatkan daftar match.
| Parameter | Tipe | Keterangan |
|---|---|---|
type | string | "new" (tanpa pesan), "conversations" (ada pesan), kosong (semua) |
curl -X GET "https://fumai.app/api/mobile/v1/fitmatch/matches?type=new" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"const res = await fetch('https://fumai.app/api/mobile/v1/fitmatch/matches?type=new', {
headers: { Authorization: `Bearer ${accessToken}` },
})
const data = await res.json()Response 200
{
"success": true,
"data": {
"newMatches": [
{
"matchId": "...",
"matchType": "LIKE",
"matchedAt": "...",
"profile": { "displayName": "Jane", "age": 25, "photos": [] }
}
],
"conversations": [
{
"matchId": "...",
"profile": { "displayName": "Bob" },
"lastMessage": { "content": "Hey!", "createdAt": "...", "isMine": false },
"unreadCount": 2
}
],
"totalMatches": 5
}
}GET /fitmatch/chat/:matchId
Mendapatkan chat room dengan pagination.
| Parameter | Tipe | Keterangan |
|---|---|---|
cursor | string | Message ID untuk pagination |
limit | number | Jumlah pesan (default: 50) |
curl -X GET "https://fumai.app/api/mobile/v1/fitmatch/chat/MATCH_ID?limit=50" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"Info: Otomatis menandai pesan yang belum dibaca sebagai read.
POST /fitmatch/chat/:matchId/messages
Kirim pesan.
Text Message
{ "content": "Hey, want to workout together?" }Image Message
{
"image": { "base64": "...", "mimeType": "image/jpeg" },
"content": "Check this out"
}Batasan: Maks 1000 karakter, image maks 5MB. Rate limit: 60/menit.
curl -X POST https://fumai.app/api/mobile/v1/fitmatch/chat/MATCH_ID/messages \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "content": "Hey, want to workout together?" }'const res = await fetch(
`https://fumai.app/api/mobile/v1/fitmatch/chat/${matchId}/messages`,
{
method: 'POST',
headers: {
Authorization: `Bearer ${accessToken}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ content: 'Hey, want to workout together?' }),
}
)GET /fitmatch/chat/:matchId/messages
Poll pesan baru.
| Parameter | Tipe | Keterangan |
|---|---|---|
after | string | ISO timestamp, ambil pesan setelah waktu ini |
POST /fitmatch/chat/:matchId/read
Tandai pesan sebagai dibaca.
DELETE /fitmatch/chat/:matchId
Unmatch — hapus match dan semua pesan.
POST /fitmatch/chat/:matchId/typing
Kirim indikator sedang mengetik.
{ "isTyping": true }Info: Kirim
isTyping: truesaat mulai mengetik,isTyping: falsesaat berhenti (debounce 3 detik direkomendasikan).
Gyms
GET /fitmatch/profile/gyms
Mendapatkan daftar gym yang ditambahkan ke profil.
Response 200
{
"success": true,
"data": {
"gyms": [
{
"id": "...",
"name": "Gold's Gym",
"branch": "Kuta",
"city": "Denpasar",
"isCustom": false,
"sortOrder": 0
}
],
"maxGyms": 5
}
}POST /fitmatch/profile/gyms
Tambah gym ke profil.
{
"gymId": "golds-gym",
"name": "Gold's Gym",
"branch": "Kuta",
"city": "Denpasar",
"isCustom": false
}Untuk custom gym:
{ "name": "My Home Gym", "isCustom": true }PUT /fitmatch/profile/gyms
Reorder atau update gym.
Reorder: { "gymIds": ["id1", "id2", "id3"] }
Update: { "id": "gymRecordId", "name": "Updated Name", "branch": "New Branch" }
DELETE /fitmatch/profile/gyms
Hapus gym dari profil.
| Parameter | Tipe | Keterangan |
|---|---|---|
id | string | Gym record ID (query parameter) |
Block & Report
POST /fitmatch/block
Block user. Otomatis: block user, deactivate match, hapus pending swipe.
{ "blockedProfileId": "clx...", "reason": "Inappropriate behavior" }GET /fitmatch/block
Mendapatkan daftar user yang di-block.
DELETE /fitmatch/block
Unblock user.
| Parameter | Tipe | Keterangan |
|---|---|---|
profileId | string | Profile ID (query parameter) |
POST /fitmatch/report
Laporkan user.
Request Body
| Field | Tipe | Wajib | Keterangan |
|---|---|---|---|
reportedProfileId | string | Ya | ID profil yang dilaporkan |
reason | string | Ya | Alasan (lihat tabel) |
details | string | Tidak | Detail tambahan |
evidence | string[] | Tidak | URL screenshot bukti |
Alasan Report
| Reason | Keterangan |
|---|---|
FAKE_PROFILE | Profil palsu/catfish |
HARASSMENT | Pelecehan atau bullying |
INAPPROPRIATE_CONTENT | Foto/pesan tidak pantas |
SPAM | Spam atau komersial |
UNDERAGE | User di bawah 18 tahun |
OFFLINE_BEHAVIOR | Perilaku tidak aman offline |
OTHER | Alasan lain |
Peringatan: 3+ laporan atau alasan
UNDERAGE→ auto-suspend. Reporter otomatis mem-block user yang dilaporkan.
GET /fitmatch/report
Mendapatkan daftar laporan yang sudah dibuat.
Settings & Verification
GET /fitmatch/settings
Mendapatkan pengaturan FitMatch.
PUT /fitmatch/settings
Update pengaturan FitMatch.
{
"status": "ACTIVE",
"showOnlineStatus": true,
"showDistance": true,
"showLastActive": true
}| Status | Keterangan |
|---|---|
ACTIVE | Terlihat di discover |
PAUSED | Tersembunyi dari discover |
DELETE /fitmatch/settings
Hapus profil FitMatch secara permanen.
{ "confirmation": "DELETE_MY_FITMATCH" }GET /fitmatch/verification
Cek status verifikasi foto.
POST /fitmatch/verification
Submit foto verifikasi (selfie).
Content-Type: multipart/form-data| Field | Tipe | Keterangan |
|---|---|---|
photo | File | Selfie (maks 5MB) |
DELETE /fitmatch/verification
Batalkan permintaan verifikasi.
Badges
GET /fitmatch/badges
Mendapatkan badge dan progress badge.
Response 200
{
"success": true,
"data": {
"badges": ["CONSISTENT", "PR_ACHIEVER"],
"progress": [
{ "badge": "PHOTO_VERIFIED", "progress": 0, "requirement": "Submit verification photo" },
{ "badge": "CONSISTENT", "earnedAt": "2026-03-15T...", "progress": 100 },
{ "badge": "VETERAN", "progress": 60, "requirement": "1+ year on Fumai" }
]
}
}Daftar Badge
| Badge | Syarat |
|---|---|
PHOTO_VERIFIED | Submit dan lolos verifikasi foto |
CONSISTENT | 4+ minggu streak workout |
PR_ACHIEVER | 10+ personal records |
VETERAN | 1+ tahun di Fumai |
EARLY_ADOPTER | 1000 user pertama |
POST /fitmatch/badges
Refresh/recalculate badge dari data workout terbaru.
curl -X POST https://fumai.app/api/mobile/v1/fitmatch/badges \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"