Skip to Content

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

FieldTipeWajibKeterangan
displayNamestringYaNama tampilan
birthDatestringYaTanggal lahir (ISO date)
genderstringYa"MALE" atau "FEMALE"
biostringTidakBio khusus FitMatch
heightnumberTidakTinggi dalam cm
lookingForstring[]TidakGender yang dicari (contoh: ["FEMALE"])
interestedInstring[]TidakDari opsi fitmatch_interest
ageMinnumberTidakUsia minimum filter
ageMaxnumberTidakUsia maksimum filter
maxDistancenumberTidakRadius maks dalam km
fitnessGoalsstring[]TidakContoh: ["MUSCLE_GAIN", "STAY_FIT"]
promptsobject[]TidakQ&A untuk profil: [{ question, answer }]

Auto-sync dari Profile

Field FitMatchSumber Profile
bioProfile.bio
heightProfile.height (dalam cm)
cityNama kota dari Profile.cityId
latitude/longitudeProfile.latitude/longitude
photosProfile.photos[]FitMatchPhoto[]
sportsProfile.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
FieldTipeWajibKeterangan
fileFileYaImage 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.

ParameterTipeKeterangan
idstringPhoto 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.

ParameterTipeKeterangan
limitnumberJumlah profil (default: 10)
excludeIdsstringComma-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

FieldTipeWajibKeterangan
targetProfileIdstringYaID profil target
swipeTypestringYa"PASS", "LIKE", atau "WORKOUT_BUDDY"
Swipe TypeKeterangan
PASSTidak tertarik
LIKETertarik (romantis)
WORKOUT_BUDDYTertarik (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.

ParameterTipeKeterangan
typestring"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.

ParameterTipeKeterangan
cursorstringMessage ID untuk pagination
limitnumberJumlah 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.

ParameterTipeKeterangan
afterstringISO 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: true saat mulai mengetik, isTyping: false saat 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.

ParameterTipeKeterangan
idstringGym 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.

ParameterTipeKeterangan
profileIdstringProfile ID (query parameter)

POST /fitmatch/report

Laporkan user.

Request Body

FieldTipeWajibKeterangan
reportedProfileIdstringYaID profil yang dilaporkan
reasonstringYaAlasan (lihat tabel)
detailsstringTidakDetail tambahan
evidencestring[]TidakURL screenshot bukti

Alasan Report

ReasonKeterangan
FAKE_PROFILEProfil palsu/catfish
HARASSMENTPelecehan atau bullying
INAPPROPRIATE_CONTENTFoto/pesan tidak pantas
SPAMSpam atau komersial
UNDERAGEUser di bawah 18 tahun
OFFLINE_BEHAVIORPerilaku tidak aman offline
OTHERAlasan 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 }
StatusKeterangan
ACTIVETerlihat di discover
PAUSEDTersembunyi 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
FieldTipeKeterangan
photoFileSelfie (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

BadgeSyarat
PHOTO_VERIFIEDSubmit dan lolos verifikasi foto
CONSISTENT4+ minggu streak workout
PR_ACHIEVER10+ personal records
VETERAN1+ tahun di Fumai
EARLY_ADOPTER1000 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"
Last updated on