๐Ÿ‹๏ธ GymOps API Documentation

https://gym.sroy.cloud/api
Inventory v1 docs: OpenAPI YAML | Postman Collection
Quick switch: Health: not checked Use any valid role header to test matching endpoints directly from this page.
๐Ÿ“˜ Reason Codes

All attendance / auth / QR endpoints emit one of the following canonical reason_code values inside data.reason_code. Mobile clients must treat these as a closed enum and key UX off them โ€” never off HTTP status alone.

reason_codeMeaning
successOperation succeeded
policy_qr_disabledPolicy does not allow QR for this flow
policy_geofence_requiredGeofence coordinates required by policy
qr_requiredDirect check-in blocked; QR mandatory
outside_geofenceCoordinates outside gym radius
qr_expiredQR token TTL passed
qr_invalidQR token signature/format invalid
qr_already_usedSingle-use token already consumed
role_not_allowedUser role cannot use this flow
user_inactiveUser account deactivated
gym_inactiveGym deactivated
membership_expiredMember's membership has expired
payment_dueMember has overdue payment and policy blocks
already_checked_inAlready has open check-in today
already_checked_outAlready completed today's session
has_dependentsCascade conflict on delete (HTTP 409)
unknown_errorFallback

QR scan / legacy attendance endpoints always reply with HTTP 200 for policy and business-rule rejections; only true transport/server faults return 4xx/5xx.

๐Ÿ” Authentication
POST /api/login Login with email & password โ–ผ

โœ… Success Response (200)

{"success": true, "message": "Login successful", "data": {"user_id": 1, "name": "Super Admin", "email": "superadmin@gymops.com", "role": "super_admin", "gym_id": null, "message": "Use X-User-Id header with value 1 for subsequent API calls"}}

โŒ Error Response (401)

{"success": false, "message": "Invalid credentials"}
GET /api/me Get current authenticated user โ–ผ

No additional parameters. Uses X-User-Id header.

โœ… Success (200) โ€” normal gym admin

{"success": true, "data": {"id": 2, "name": "Gym Admin", "email": "admin@testgym.com", "role": "gym_admin", "gym_id": 1, "status": "active", "gym": {"id": 1, "name": "Test Gym", "status": "active"}}, "subscription_warning": false, "warning_code": null, "warning_message": null, "days_to_expiry": 12, "subscription_expiry_at": "2026-05-14T23:59:59+05:30"}

โœ… Success (200) โ€” member with assigned programs

{"success": true, "data": {"id": 4, "name": "Alice Member", "role": "member", "member_type": "trainer_assigned", "trainer_id": 3, "trainer": {"id": 3, "name": "John Trainer", "email": "trainer@example.com"}, "section_id": 1, "section_name": "Strength", "sections": [{"id": 1, "name": "Strength", "type": "gym"}, {"id": 2, "name": "Cardio", "type": "sport"}], "memberships": [{"id": 11, "member_id": 4, "trainer_id": 3, "section_id": 1, "program_id": 1, "section_name": "Strength", "program_name": "Strength", "status": "active", "member_type": "trainer_assigned", "plan": "monthly", "amount": "100.00", "start_date": "2026-05-04", "expiry_date": "2026-06-03", "section": {"id": 1, "name": "Strength", "type": "gym"}}], "gym": {"id": 1, "name": "Test Gym", "status": "active"}}, "subscription_warning": false}

โœ… Success (200) โ€” trainer with assigned programs

{"success": true, "data": {"id": 3, "name": "John Trainer", "role": "trainer", "availability_summary": {"has_availability": true, "weekly_days_configured": 2, "total_weekly_slots": 3, "next_available_at": "2026-06-03T06:00:00+05:30", "today_windows": [{"start_time": "06:00:00", "end_time": "08:00:00"}]}, "section_id": 1, "section_name": "Strength", "sections": [{"id": 1, "name": "Strength", "type": "gym"}, {"id": 2, "name": "Cardio", "type": "sport"}], "memberships": [{"id": 21, "member_id": null, "trainer_id": 3, "section_id": 1, "program_id": 1, "section_name": "Strength", "program_name": "Strength", "status": "active", "member_type": null, "section": {"id": 1, "name": "Strength", "type": "gym"}}], "gym": {"id": 1, "name": "Test Gym", "status": "active"}}, "subscription_warning": false}

โš ๏ธ Success (200) โ€” active gym expiring soon

{"success": true, "data": {"id": 2, "name": "Gym Admin", "role": "gym_admin", "gym_id": 1, "gym": {"id": 1, "name": "Test Gym", "status": "active"}}, "subscription_warning": true, "warning_code": "SUBSCRIPTION_EXPIRING_SOON", "warning_message": "Gym subscription will expire within 2 days. Please renew soon.", "days_to_expiry": 2, "subscription_expiry_at": "2026-05-04T23:59:59+05:30"}

โš ๏ธ Success (200) โ€” active gym already expired

{"success": true, "data": {"id": 2, "name": "Gym Admin", "role": "gym_admin", "gym_id": 1, "gym": {"id": 1, "name": "Test Gym", "status": "active"}}, "subscription_warning": true, "warning_code": "SUBSCRIPTION_EXPIRED", "warning_message": "Gym subscription has expired. Contact Super Admin.", "days_to_expiry": -1, "subscription_expiry_at": "2026-05-01T23:59:59+05:30"}

โœ… Success (200) โ€” super admin

{"success": true, "data": {"id": 1, "name": "Super Admin", "email": "superadmin@gymops.com", "role": "super_admin", "gym_id": null, "status": "active", "gym": null}}
POST /api/change-password Change your password โ–ผ

โœ… Success Response (200)

{"success": true, "message": "Password changed successfully"}
๐Ÿ“ฑ App Release (APK Management)
GET /api/public/app-release/latest Public latest active Android release โ–ผ

No auth required. Returns latest active Android APK release.

โœ… Success (200)

{"success": true, "data": {"id": 1, "title": "AhaNexa Android App", "version": "1.0.4", "build_number": "14", "notes": "Bug fixes and attendance improvements", "platform": "android", "file_name": "ahanexa-v1.0.4.apk", "file_url": "https://gym.sroy.cloud/storage/app-releases/ahanexa-v1.0.4.apk", "file_size": 24567890, "file_size_label": "23.4 MB", "is_active": true, "uploaded_at": "2026-05-02T10:20:30Z"}}

โŒ Not Found (404)

{"success": false, "message": "No active app release found"}
GET /api/super-admin/app-release Get current active release (super admin) โ–ผ

Requires super admin `X-User-Id`.

โœ… Success (200) with data

{"success": true, "data": {"id": 1, "title": "AhaNexa Android App", "version": "1.0.4", "build_number": "14", "notes": "Bug fixes", "platform": "android", "file_name": "ahanexa-v1.0.4.apk", "file_url": "https://gym.sroy.cloud/storage/app-releases/ahanexa-v1.0.4.apk", "file_size": 24567890, "file_size_label": "23.4 MB", "is_active": true, "uploaded_at": "2026-05-02T10:20:30Z"}}

โœ… Success (200) with null

{"success": true, "data": null}
POST /api/super-admin/app-release Create new APK release (multipart/form-data) โ–ผ

๐Ÿ“ multipart/form-data fields

title= AhaNexa Android App
version= 1.0.4
build_number= 14 (optional)
notes= Bug fixes and attendance improvements (optional)
platform= android (optional)
file= ahanexa-v1.0.4.apk (required, max 100MB)

โœ… Success (201)

{"success": true, "message": "APK release created successfully", "data": {"id": 1, "title": "AhaNexa Android App", "version": "1.0.4", "build_number": "14", "notes": "Bug fixes and attendance improvements", "platform": "android", "file_name": "ahanexa-v1.0.4-20260502102030.apk", "file_url": "https://gym.sroy.cloud/storage/app-releases/ahanexa-v1.0.4-20260502102030.apk", "file_size": 24567890, "file_size_label": "23.4 MB", "is_active": true, "uploaded_at": "2026-05-02T10:20:30Z"}}

โŒ Validation (422)

{"success": false, "message": "Validation failed", "errors": {"file": ["The file field must not be greater than 102400 kilobytes."]}}

โŒ Payload Too Large (413)

{"success": false, "message": "Uploaded file exceeds server limit. Maximum allowed size is 100MB.", "data": {"reason_code": "payload_too_large", "max_upload_mb": 100}}

Use Postman/cURL for file upload testing from docs UI.

PUT /api/super-admin/app-release/{id} Update metadata and optionally replace APK file โ–ผ

๐Ÿ“ multipart/form-data fields

title= AhaNexa Android App
version= 1.0.5
build_number= 15 (optional)
notes= Patch release (optional)
platform= android (optional)
file= ahanexa-v1.0.5.apk (optional replacement, max 100MB)

โœ… Success (200)

{"success": true, "message": "APK release updated successfully", "data": {"id": 1, "title": "AhaNexa Android App", "version": "1.0.5", "build_number": "15", "notes": "Patch release", "platform": "android", "file_name": "ahanexa-v1.0.5-20260502113000.apk", "file_url": "https://gym.sroy.cloud/storage/app-releases/ahanexa-v1.0.5-20260502113000.apk", "file_size": 25200000, "file_size_label": "24.0 MB", "is_active": true, "uploaded_at": "2026-05-02T10:20:30Z"}}
DELETE /api/super-admin/app-release/{id} Delete release and stored APK file โ–ผ

โœ… Success (200)

{"success": true, "message": "APK release deleted successfully"}
๐Ÿ“ฆ Inventory v1
GET /api/v1/gyms/{gym_id}/inventory List inventory items โ–ผ

โœ… Success Response (200)

{"success": true, "message": "Inventory items fetched successfully", "data": [{"id": 1, "name": "Treadmill X", "sku": "TR-100", "custom_fields": {"weight_kg": 60, "brand": "FitPro"}, "weight_kg": 60}], "meta": {"total": 2}}
POST /api/v1/gyms/{gym_id}/inventory Create inventory item (admin) โ–ผ

โœ… Success Response (201)

{"success": true, "message": "Inventory item created successfully", "data": {"id": 3, "name": "Air Bike", "sku": "AB-200", "custom_fields": {"category": "cardio", "weight_kg": 18.5}, "weight_kg": 18.5}}

โŒ Duplicate SKU (422)

{"error":{"code":"validation_failed","message":"Validation failed","details":{"sku":["The sku has already been taken."]}}}
GET /api/v1/gyms/{gym_id}/inventory/{id} Show inventory item details โ–ผ

โœ… Success Response (200)

{"success": true, "data": {"id": 1, "name": "Treadmill X", "sku": "TR-100", "custom_fields": {"brand": "FitPro", "weight_kg": 60}, "weight_kg": 60}}
PUT /api/v1/gyms/{gym_id}/inventory/{id} Update inventory item โ–ผ

โœ… Success Response (200)

{"success": true, "message": "Inventory item updated successfully", "data": {"id": 1, "custom_fields": {"weight_kg": 62}, "weight_kg": 62}}

โŒ Duplicate SKU (422)

{"error":{"code":"validation_failed","message":"Validation failed","details":{"sku":["The sku has already been taken."]}}}
DELETE /api/v1/gyms/{gym_id}/inventory/{id} Delete inventory item โ–ผ

โœ… Success Response (200)

{"success": true, "message": "Inventory item deleted successfully"}
POST /api/v1/gyms/{gym_id}/inventory/bulk-update Bulk update quantities/status โ–ผ

Use Raw JSON for multiple updates payload.

โœ… Success Response (200)

{"success": true, "message": "Inventory updated in bulk"}
GET /api/v1/gyms/{gym_id}/inventory/{id}/history Get item audit history โ–ผ

โœ… Success Response (200)

{"success": true, "data": [{"action":"updated"}]}
GET /api/v1/gyms/{gym_id}/inventory/filters-meta Get categories/suppliers/status filters โ–ผ

โœ… Success Response (200)

{"success": true, "data": {"categories":[],"suppliers":[],"statuses":["in_working_condition","not_working","not_available"]}}
GET /api/v1/gyms/{gym_id}/inventory/{item_id}/images List image metadata for an inventory item โ–ผ

โœ… Success Response (200)

{"success": true, "data": [{"id": 1, "inventory_item_id": 1, "file_name": "photo.jpg", "mime_type": "image/jpeg", "size_bytes": 24512, "download_url": "https://gym.sroy.cloud/api/v1/gyms/1/inventory/1/images/1", "created_at": "2026-04-29T10:00:00Z"}]}
POST /api/v1/gyms/{gym_id}/inventory/{item_id}/images Upload one or more item images โ–ผ

Use Postman or cURL multipart with images[] files for actual upload bytes.

โœ… Success Response (201)

{"success": true, "message": "Inventory images uploaded successfully", "data": [{"id": 11, "file_name":"photo.jpg", "mime_type":"image/jpeg", "size_bytes":24512, "download_url":"https://gym.sroy.cloud/api/v1/gyms/1/inventory/1/images/11"}]}
GET /api/v1/gyms/{gym_id}/inventory/{item_id}/images/{image_id} Stream inventory image bytes (Content-Type: image/*) โ–ผ
Tip: open this URL directly in browser to view image bytes/thumbnail.

โœ… Success Response (200)

Binary image stream with image Content-Type
DELETE /api/v1/gyms/{gym_id}/inventory/{item_id}/images/{image_id} Delete one image row from an inventory item โ–ผ

โœ… Success Response (200)

{"success": true, "message": "Inventory image deleted successfully", "data": {"id": 1}}
GET /api/v1/gyms/{gym_id}/inventory-requests List inventory requests โ–ผ

โœ… Success Response (200)

{"success": true, "data": [{"id":1,"status":"pending"}]}
POST /api/v1/gyms/{gym_id}/inventory-requests Create inventory request (member/trainer) โ–ผ

โœ… Success Response (201)

{"success": true, "message": "Inventory request created successfully", "data": {"id": 1, "status": "pending"}}
PUT /api/v1/gyms/{gym_id}/inventory-requests/{id} Update inventory request (admin) โ–ผ

โœ… Success Response (200)

{"success": true, "message": "Inventory request updated successfully"}
POST /api/v1/gyms/{gym_id}/inventory-requests/{id}/resolve Resolve inventory request (admin) โ–ผ

โœ… Success Response (200)

{"success": true, "message": "Inventory request resolved successfully"}
GET /api/v1/gyms/{gym_id}/inventory/audit-logs List inventory audit logs (admin) โ–ผ

โœ… Success Response (200)

{"success": true, "message": "Inventory audit logs fetched successfully", "data": [{"action":"request_change"}]}
๐Ÿข Super Admin โ€” Gym Management
POST /api/super-admin/gyms Create a new gym with unique gym_id โ–ผ

โœ… Success Response (201)

{"success": true, "message": "Gym created successfully with admin account", "data": {"gym": {"id": 2, "gym_id": "GYM-AB12CD34", "name": "PowerGym", "gym_email": "powergym@example.com", "status": "active"}, "admin": {"user_id": 5, "name": "PowerGym Admin", "email": "admin.powergym@example.com"}, "admin_user_id": 5, "admin_email": "admin.powergym@example.com"}}
GET /api/super-admin/gyms List all gyms with member/trainer counts โ–ผ

โœ… Success Response (200)

{"success": true, "data": {"data": [{"id": 1, "gym_id": "GYM-DEMO0001", "name": "FitLife Gym", "status": "active", "members_count": 2, "trainers_count": 1}], "current_page": 1, "total": 1}}
GET /api/super-admin/gyms/{id} Get single gym details โ–ผ

โœ… Success Response (200)

{"success": true, "data": {"id": 1, "gym_id": "GYM-DEMO0001", "name": "FitLife Gym", "gym_email": "fitlife@example.com", "status": "active", "members_count": 2, "trainers_count": 1, "gym_admin": {"id": 2, "email": "admin@fitlife.com", "name": "FitLife Gym Admin", "status": "active"}}}
PUT /api/super-admin/gyms/{id} Update basic gym profile fields โ–ผ

โœ… Success (200)

{"success": true, "message": "Gym profile updated successfully", "data": {"id": 1, "gym_id": "GYM-DEMO0001", "name": "FitLife Elite", "city": "Mumbai"}}
GET /api/super-admin/gyms/{gymId}/admins List all gym admins for one gym โ–ผ

โœ… Success (200)

{"success": true, "data": [{"id": 12, "name": "Admin A", "email": "a@gym.com", "status": "active", "gym_id": 1, "created_at": "2026-05-04T06:00:00.000000Z", "updated_at": "2026-05-04T06:00:00.000000Z"}]}
POST /api/super-admin/gyms/{gymId}/admins Create a gym admin (supports multi-admin per gym) โ–ผ

โœ… Success (201)

{"success": true, "message": "Gym admin created successfully", "data": {"id": 13, "name": "Admin C", "email": "admin.c@example.com", "status": "active", "gym_id": 1}}

โŒ Validation Error (422)

{"success": false, "message": "Validation failed", "errors": {"email": ["The email has already been taken."]}}
PATCH /api/super-admin/gyms/{gymId}/admins/{adminId} Update gym admin name/email/status โ–ผ

โœ… Success (200)

{"success": true, "message": "Gym admin updated successfully", "data": {"id": 13, "name": "Admin C Updated", "email": "admin.c.updated@example.com", "status": "active", "gym_id": 1}}

โŒ Cross Gym (403)

{"success": false, "message": "Forbidden cross-gym admin update"}

โŒ Validation (422)

{"success": false, "message": "Validation failed", "errors": {"fields": ["At least one of name, email, status is required."]}}
PATCH /api/super-admin/gyms/{gymId}/admins/{adminId}/deactivate Deactivate scoped gym admin โ–ผ

โœ… Success (200)

{"success": true, "message": "Gym admin deactivated successfully", "data": {"id": 13, "name": "Admin C", "email": "admin.c@example.com", "status": "inactive", "gym_id": 1}}

โŒ Not Found (404)

{"success": false, "message": "Gym admin not found"}
PATCH /api/super-admin/gyms/{gymId}/admins/{adminId}/activate Activate scoped gym admin โ–ผ

โœ… Success (200)

{"success": true, "message": "Gym admin activated successfully", "data": {"id": 13, "name": "Admin C", "email": "admin.c@example.com", "status": "active", "gym_id": 1}}

โŒ Not Found (404)

{"success": false, "message": "Gym admin not found"}
DELETE /api/super-admin/gyms/{gymId}/admins/{adminId} Delete scoped gym admin (soft delete) โ–ผ

โœ… Success (200)

{"success": true, "message": "Gym admin deleted successfully", "data": {"id": 13, "gym_id": 1}}

โŒ Last Active Admin (409)

{"success": false, "message": "Cannot delete the last active gym admin", "data": {"reason_code": "last_active_admin"}}
PATCH /api/super-admin/gyms/{id}/activate Activate a gym โ–ผ

โœ… Success (200)

{"success": true, "message": "Gym activated successfully"}
PATCH /api/super-admin/gyms/{id}/deactivate Deactivate a gym โ–ผ

โœ… Success (200)

{"success": true, "message": "Gym deactivated successfully"}
PUT /api/super-admin/gyms/{id}/subscription Assign subscription plan to gym โ–ผ

โœ… Success (200, auto expiry)

{"success": true, "message": "Subscription assigned successfully", "data": {"subscription_expiry": "2027-04-30", "expiry_source": "auto", "gym": {"id": 1, "subscription_plan": "yearly"}}}

โœ… Success (200, manual override)

{"success": true, "message": "Subscription assigned successfully", "data": {"subscription_expiry": "2027-12-31", "expiry_source": "manual", "gym": {"id": 1, "subscription_plan": "yearly"}}}
PATCH /api/super-admin/gyms/{id}/subscription-expiry Manual subscription expiry update with audit reason โ–ผ

โœ… Success (200)

{"success": true, "message": "Subscription expiry updated successfully", "data": {"gym_id": 1, "old_expiry": "2027-04-30", "subscription_expiry": "2027-06-30", "changed_by": 1, "reason": "Approved extension", "source": "manual"}}
GET /api/super-admin/gyms/{id}/subscription-audits Subscription expiry audit history for one gym โ–ผ

โœ… Success (200)

{"success": true, "message": "Subscription audit history fetched successfully", "data": [{"id": 14, "gym_id": 1, "old_expiry": "2027-04-30", "new_expiry": "2027-06-30", "changed_by": 1, "changed_by_name": "Super Admin", "changed_by_email": "superadmin@gymops.com", "reason": "Approved extension", "source": "manual", "changed_at": "2026-04-30T08:40:00.000000Z"}], "meta": {"current_page": 1, "last_page": 1, "per_page": 15, "total": 1}}
๐Ÿ’ฐ Super Admin โ€” SaaS Revenue & Payments
GET /api/super-admin/saas/overview Total gyms, members, revenue overview โ–ผ

โœ… Success (200)

{"success": true, "data": {"total_gyms": 1, "active_gyms": 1, "inactive_gyms": 0, "monthly_saas_revenue": "12000.00", "gyms": [{"gym_id": "GYM-DEMO0001", "name": "FitLife Gym", "members_count": 2, "status": "active"}]}}
GET /api/super-admin/saas/payment-status Payment status per gym โ–ผ
GET /api/super-admin/saas/expiring-gyms Gyms expiring within 30 days โ–ผ
POST /api/super-admin/gym-payments Record gym subscription payment โ–ผ

โœ… Success (201)

{"success": true, "message": "Payment recorded successfully", "data": {"id": 1, "gym_id": 1, "amount": "12000.00", "plan": "yearly", "invoice_number": "INV-20260331-AB12CD", "status": "paid"}}
GET /api/super-admin/gym-payments/{gymId}/history Gym payment history โ–ผ
GET /api/super-admin/gym-payments All gym payments. status=due acts as due-dataset alias (same source as /gym-payments/due, excludes active paid+valid gyms without pending liability) โ–ผ

โœ… Success (200) โ€” status=all/paid

{
    "success": true,
    "data": {
        "data": [
            {
                "id": 12,
                "gym_id": 1,
                "gym_name": "FitLife Gym",
                "gym_code": "GYM-DEMO0001",
                "amount": 5000,
                "plan": "monthly",
                "status": "paid",
                "payment_date": "2026-05-01",
                "valid_from": "2026-05-01",
                "valid_to": "2026-06-01",
                "notes": "Monthly renewal",
                "created_at": "2026-05-01T10:00:00+00:00",
                "gym": {"id": 1, "name": "FitLife Gym", "gym_id": "GYM-DEMO0001", "status": "active"}
            }
        ],
        "current_page": 1,
        "last_page": 4,
        "per_page": 15,
        "total": 57
    },
    "meta": {
        "monthly_total": 12345,
        "filtered_total": 54321
    }
}

โœ… Success (200) โ€” status=due alias

{
    "success": true,
    "data": {
        "data": [
            {
                "gym_id": 3,
                "gym_code": "GYM-003",
                "gym_name": "Expired Gym",
                "due_amount": 5000,
                "due_date": "2026-03-15",
                "overdue_days_max": 46,
                "last_due_date": "2026-03-15"
            }
        ],
        "current_page": 1,
        "last_page": 1,
        "per_page": 15,
        "total": 1
    },
    "meta": {
        "monthly_total": 0,
        "filtered_total": 5000,
        "due_gyms_count": 1,
        "total_due_amount": 5000
    }
}
GET /api/super-admin/gym-payments/summary Per-gym payment summary with totals โ–ผ

โœ… Success (200)

{"success": true, "data": [{"gym_id": 1, "gym_code": "GYM-DEMO0001", "name": "FitLife Gym", "status": "active", "total_paid": "12000.00", "total_payments": 1, "last_payment_date": "2026-03-31"}]}
GET /api/super-admin/gym-payments/{paymentId}/view View invoice data as JSON โ–ผ
GET /api/super-admin/gym-payments/{paymentId}/invoice Download gym invoice PDF โ–ผ
POST /api/super-admin/gym-payments ๐Ÿ†• Record gym subscription payment (auto-calc validity, AHX receipt) โ–ผ

โœ… 201 Created (cash/upi with reference)

{"success": true, "message": "Payment recorded successfully.", "data": {"id": 5, "gym_id": 1, "gym_name": "FitLife Gym", "gym_code": "GYM-DEMO0001", "amount": 5000.0, "payment_mode": "upi", "plan": "monthly", "status": "paid", "payment_date": "2026-05-02", "valid_from": "2026-05-02", "valid_to": "2026-06-02", "reference_no": "UPI202605020001", "utr_no": null, "cheque_no": null, "cheque_date": null, "notes": null, "created_at": "2026-05-02T10:00:00+05:30"}}

โŒ 422 โ€” UPI without reference_no/utr_no

{"success": false, "message": "reference_no or utr_no is required for the selected payment mode.", "errors": {"reference_no": ["Provide reference_no or utr_no for this payment mode."], "utr_no": ["Provide reference_no or utr_no for this payment mode."]}}

โŒ 422 โ€” cheque without cheque_no/cheque_date

{"success": false, "message": "cheque_no and cheque_date are required for cheque mode.", "errors": {"cheque_no": ["The cheque_no field is required for cheque mode."], "cheque_date": ["The cheque_date field is required for cheque mode."]}}

โŒ 422 โ€” custom plan without valid_to

{"success": false, "message": "The valid to field is required when plan is custom.", "errors": {"valid_to": ["The valid to field is required when plan is custom."]}}
DELETE /api/super-admin/gym-payments/{paymentId} Delete a gym payment record โ–ผ

โœ… 200 OK

{"success": true, "message": "Gym payment deleted successfully.", "data": {"id": 15}}

โŒ 404 Not Found

{"message": "No query results for model [App\\Models\\GymPayment] 999999"}
GET /api/super-admin/gyms/{id}/payment-status ๐Ÿ†• Single gym payment status (days remaining / overdue) โ–ผ

โœ… Paid

{"success": true, "data": {"gym_id": 1, "gym_name": "FitLife Gym", "current_status": "paid", "days_remaining": 30, "days_overdue": 0, "next_due_date": "2026-05-30", "last_payment": {"id": 5, "amount": 5000.0, "plan": "monthly", "receipt_number": "AHX-202604-000001"}}}

โš ๏ธ Due

{"success": true, "data": {"gym_id": 2, "gym_name": "Old Gym", "current_status": "due", "days_remaining": 0, "days_overdue": 15, "next_due_date": "2026-04-15", "last_payment": null}}
GET /api/super-admin/gym-payments/due ๐Ÿ†• Actual unpaid liability gyms list (single source of truth) โ–ผ

โœ… 200 OK

{"success": true, "data": {"due_gyms_count": 2, "total_due_amount": 10000.0, "gyms": [{"gym_id": 3, "gym_code": "GYM-003", "gym_name": "Expired Gym", "due_amount": 5000.0, "due_date": "2026-03-15", "overdue_days_max": 46, "last_due_date": "2026-03-15"}, {"gym_id": 5, "gym_code": "GYM-005", "gym_name": "New Gym (No Payment)", "due_amount": 5000.0, "due_date": null, "overdue_days_max": 0, "last_due_date": null}]}}
GET /api/super-admin/gym-payments/{paymentId}/receipt ๐Ÿ†• Structured receipt payload (for Flutter PDF generation) โ–ผ

โœ… 200 OK

{"success": true, "data": {"receipt_number": "AHX-202604-000001", "issued_at": "2026-04-30T10:00:00+05:30", "brand": {"name": "AhaNexa", "logo_text": "AhaNexa", "logo_url": null}, "gym": {"id": 1, "gym_id": "GYM-DEMO0001", "name": "FitLife Gym", "email": "fitlife@example.com", "phone": "9999999999", "address": "123 Main St, Mumbai, Maharashtra, India"}, "payment": {"id": 5, "amount": 5000.0, "plan": "monthly", "payment_date": "2026-04-30", "valid_from": "2026-04-30", "valid_to": "2026-05-30", "status": "paid", "notes": null}, "issued_by": {"name": "Super Admin", "email": "super@ahanexaplatform.com"}, "footer": "Issued by AhaNexa Platform"}}
GET /api/super-admin/gym-payments/{gymId}/history ๐Ÿ†• Gym payment history (paginated, filterable) โ–ผ

โœ… 200 OK

{"success": true, "data": [{"id": 5, "gym_id": 1, "gym_name": "FitLife Gym", "amount": 5000.0, "plan": "monthly", "payment_date": "2026-04-30", "valid_from": "2026-04-30", "valid_to": "2026-05-30", "status": "paid", "receipt_number": "AHX-202604-000001"}], "meta": {"current_page": 1, "last_page": 1, "per_page": 15, "total": 1}}
GET /api/super-admin/dashboard Super Admin Dashboard โ–ผ

โœ… Success (200)

{"success": true, "data": {"total_gyms": 1, "active_gyms": 1, "inactive_gyms": 0, "total_revenue": "12000.00", "monthly_revenue": "12000.00", "top_gyms": [{"id": 1, "gym_id": "GYM-DEMO0001", "name": "FitLife Gym", "status": "active", "members_count": 2}], "expiry_alerts": []}}
๐Ÿ”‘ Super Admin โ€” Password Management
PUT /api/super-admin/users/{userId}/password Set password for any user โ–ผ

โœ… Success (200)

{"success": true, "message": "Password updated successfully for John Doe", "data": {"user_id": 2, "name": "John Doe", "email": "john@example.com", "role": "gym_admin"}}

โŒ Validation Error (422)

{"success": false, "message": "Validation failed", "errors": {"password": ["The password confirmation does not match."]}}
PUT /api/super-admin/gyms/{gymId}/admin-password Set/create gym admin password (auto-creates admin if none exists) โ–ผ

โœ… Admin Exists โ€” Password Updated (200)

{"success": true, "message": "Password updated for admin of FitLife Gym", "data": {"user_id": 2, "name": "FitLife Gym Admin", "email": "fitlife@example.com", "created": false}}

โœ… No Admin โ€” Admin Created (201)

{"success": true, "message": "Admin account created for FitLife Gym", "data": {"user_id": 5, "name": "FitLife Gym Admin", "email": "fitlife@example.com", "created": true}}

โŒ No Email on Gym (422)

{"success": false, "message": "Cannot create admin: gym has no contact email. Update gym_email first."}
๐Ÿ‘ฅ Gym Admin โ€” User Management
POST /api/gym-admin/trainers Add a new trainer โ–ผ

โœ… Success (201)

{"success": true, "message": "Trainer added successfully", "data": {"id": 6, "name": "Mike Trainer", "email": "mike.trainer@example.com", "role": "trainer", "trainer_salary": "30000.00"}}
POST /api/gym-admin/members Add a new member and auto-create onboarding payment โ–ผ

โœ… Success (201)

{"success": true, "message": "Member added successfully", "data": {"id": 7, "name": "Charlie Member", "role": "member", "member_type": "self", "fitness_goal": "General Fitness", "payment_components": {"membership_amount": 2000, "one_time_registration_fee": 300, "total_amount": 2300, "apply_registration_fee": true, "amount": 2300}, "onboarding_payment": {"amount": "2300.00", "membership_amount": "2000.00", "one_time_registration_fee": "300.00", "total_amount": "2300.00", "apply_registration_fee": true, "section_id": 3, "notes": "Initial membership payment during onboarding"}}}
GET /api/gym-admin/users List users with pagination, search & program filter โ–ผ

โœ… Success (200) โ€” Paginated users with full program info

{"success": true, "data": {"current_page": 1, "data": [{"id": 5, "name": "Anjali Das", "role": "member", "status": "active", "section_id": 3, "section_name": "Ladies Multi Gym", "sections": [{"id": 3, "name": "Ladies Multi Gym", "type": "gym"}, {"id": 8, "name": "Top Program", "type": "sport"}], "memberships": [{"id": 11, "member_id": 5, "trainer_id": 3, "section_id": 3, "program_id": 3, "section_name": "Ladies Multi Gym", "program_name": "Ladies Multi Gym", "status": "active", "member_type": "trainer_assigned"}]}, {"id": 3, "name": "John Trainer", "role": "trainer", "section_id": 3, "section_name": "Ladies Multi Gym", "sections": [{"id": 3, "name": "Ladies Multi Gym", "type": "gym"}], "memberships": [{"id": 7, "member_id": null, "trainer_id": 3, "section_id": 3, "program_id": 3, "section_name": "Ladies Multi Gym", "program_name": "Ladies Multi Gym", "status": "active", "member_type": null}]}], "from": 1, "to": 20, "total": 45, "per_page": 20, "last_page": 3}}

Program filter: ?role=member&section_id=3&per_page=20

{"success": true, "data": {"current_page": 1, "data": [...], "total": 12, "per_page": 20, "last_page": 1}}

Search: ?role=member&section_id=3&search=anj&per_page=20

{"success": true, "data": {"current_page": 1, "data": [{"id": 5, "name": "Anjali Das", ...}], "total": 1, "per_page": 20, "last_page": 1}}
GET /api/gym-admin/users/{id} Get user details โ–ผ

Response now includes sections[] (all active assigned programs) and memberships[] for member/trainer users.

PUT /api/gym-admin/users/{id} Update user details โ–ผ

โœ… Success (200)

{"success": true, "message": "User updated successfully", "data": {"id": 5, "name": "Updated Member Name", "email": "newemail@example.com", "phone": "9876543210", "address": "123 New Street, City, State 12345", "gender": "male", "emergency_contact": "Mom - 555-1234-5678", "role": "member", "gym_id": 1, "status": "active"}}

โŒ Validation Error (422)

{"success": false, "message": "Validation failed", "errors": {"email": ["The email field must be a valid email address."]}}

โŒ Unchanged Email (422)

{"success": false, "message": "Email is unchanged", "error": "The new email must be different from the current email"}
DELETE /api/gym-admin/users/{id} Delete a user (trainer/member) โ–ผ

โœ… Success (200) โ€” Force Delete

{"success": true, "message": "User force-deleted safely", "data": {"force_mode": true, "counts": {"memberships_cancelled": 1, "trainer_assignments_archived": 0, "member_trainer_links_detached": 1, "membership_trainer_links_detached": 0, "member_payments_kept": 1, "section_membership_payments_kept": 0, "users_soft_deleted": 1}}}

โŒ Blocked (409) โ€” Default Safe Mode

{"success": false, "message": "Cannot delete: active dependents exist. Retry with force=1 for safe archival.", "data": {"reason_code": "has_dependents", "members_count": 1, "trainers_count": 0, "force_supported": true}}

โŒ Forbidden (403) โ€” Cross Gym

{"success": false, "message": "You are not allowed to delete users from another gym", "data": {"reason_code": "forbidden_cross_gym"}}
PATCH /api/gym-admin/users/{id}/activate Activate a user โ–ผ
PATCH /api/gym-admin/users/{id}/deactivate Deactivate a user โ–ผ
PUT /api/gym-admin/users/{id}/password Reset password for member/trainer in same gym โ–ผ
PATCH /api/gym-admin/members/{id}/membership-expiry Manual override for member membership expiry โ–ผ
๐Ÿ‹๏ธ Gym Admin โ€” Members & Trainer Management
POST /api/gym-admin/members/{member}/send-email Gym admin sends a transactional email to one of their own members via AhaNexa SMTP โ–ผ
PATCH /api/gym-admin/members/{memberId}/assign-trainer Assign trainer to member โ–ผ
PATCH /api/gym-admin/members/{memberId}/remove-trainer Remove trainer from member โ–ผ
PATCH /api/gym-admin/members/{memberId}/fitness-goal Set member's fitness goal โ–ผ
GET /api/gym-admin/trainers List trainers with member counts โ–ผ
GET /api/gym-admin/trainers/{trainerId}/members View trainer's assigned members โ–ผ
POST /api/gym-admin/trainers/{trainerId}/assign-members Assign multiple members to trainer โ–ผ
PUT /api/v1/gym-admin/trainers/{trainer}/availability Upsert weekly availability. Use ?mode=replace (or replace=true body) to treat payload as source-of-truth and clear omitted days. โ–ผ
POST /api/v1/gym-admin/trainers/{trainer}/availability/overrides Create one or many date overrides for a trainer โ–ผ
DELETE /api/v1/gym-admin/trainers/{trainer}/availability/overrides/{overrideId} Soft delete a trainer availability override โ–ผ
GET /api/v1/gym-admin/trainers/availability/calendar Planner-ready trainer availability grouped by trainer and date โ–ผ
๐Ÿ“ Gym Admin โ€” Location Setup
POST /api/gym-admin/location Set gym geo-fence location โ–ผ
GET /api/gym-admin/location Get gym location settings โ–ผ
๐Ÿ“… Attendance System (Geo-Fenced)
POST /api/attendance/check-in Check in with GPS location โ–ผ

โœ… Success (200)

{"success": true, "message": "Checked in successfully", "data": {"attendance": {"id": 1, "user_id": 3, "gym_id": 1, "date": "2026-03-31", "time_in": "09:30:00", "lat_in": "19.07600000", "long_in": "72.87770000", "distance_in": "0.00", "status": "checked_in"}, "distance_from_gym": "0.00m"}}

โŒ Geo-fence Error (403)

{"success": false, "message": "You are 150.00m away from gym. Must be within 50m.", "data": {"distance": 150.00, "allowed_radius": 50}}
POST /api/attendance/check-out Check out with GPS location โ–ผ
GET /api/attendance/my-status Get today's check-in status โ–ผ

No additional parameters. Uses X-User-Id header.

โœ… Checked In (200)

{"success": true, "data": {"checked_in": true, "attendance": {"id": 1, "date": "2026-03-31", "time_in": "09:30:00", "time_out": null, "status": "checked_in"}}}

โ„น๏ธ Not Checked In (200)

{"success": true, "data": {"checked_in": false, "attendance": null}}
GET /api/attendance/my-history Get my attendance history (all dates) โ–ผ

Optional pagination. Uses X-User-Id header.

โœ… Success (200)

{"success": true, "data": {"data": [{"id": 12, "date": "2026-03-30", "time_in": "09:12:00", "time_out": "18:03:00", "status": "checked_out"}], "current_page": 1, "total": 15}}
POST /api/attendance/admin/check-in Admin checks in a user (no geo-fence) โ–ผ

โœ… Success (200)

{"success": true, "message": "User checked in by admin", "data": {"attendance": {"id": 5, "user_id": 3, "gym_id": 1, "date": "2026-03-31", "time_in": "09:30:00", "status": "checked_in"}}}
POST /api/attendance/admin/check-out Admin checks out a user โ–ผ

โœ… Success (200)

{"success": true, "message": "User checked out by admin", "data": {"attendance": {"id": 5, "user_id": 3, "gym_id": 1, "date": "2026-03-31", "time_in": "09:30:00", "time_out": "17:00:00", "status": "checked_out"}}}
GET /api/attendance/daily Daily attendance report โ–ผ
GET /api/attendance/monthly Monthly attendance report โ–ผ
GET /api/attendance/user/{userId} User attendance history โ–ผ
๐Ÿ’ณ Member Payment Management
GET /api/member/my-payments Member-only unified payment history (member + legacy membership payments) โ–ผ

โœ… Success (200)

{"success": true, "data": [{"id": 12, "member_id": 4, "amount": "2000.00", "plan": "monthly", "payment_mode": "upi", "payment_date": "2026-04-29", "valid_from": "2026-04-29", "valid_to": "2026-05-29", "invoice_number": "MP-20260429-000012", "status": "paid", "notes": "April payment", "section_id": 3, "section_name": "Yoga", "member_sections": [{"id": 11, "name": "AssignFlow"}, {"id": 3, "name": "Yoga"}], "all_section_names": "AssignFlow, Yoga", "payment_source": "member_payment", "created_at": "2026-04-30T13:43:51.000000Z", "updated_at": "2026-04-30T13:43:51.000000Z"}, {"id": "smp-17", "member_id": 4, "amount": "1800.00", "plan": "monthly", "payment_mode": "upi", "payment_date": "2026-04-15", "valid_from": "2026-04-15", "valid_to": "2026-05-14", "invoice_number": "SMP-20260415-000017", "status": "paid", "notes": "legacy section payment", "section_id": 11, "section_name": "AssignFlow", "member_sections": [{"id": 11, "name": "AssignFlow"}, {"id": 3, "name": "Yoga"}], "all_section_names": "AssignFlow, Yoga", "payment_source": "section_membership_payment", "created_at": "2026-04-15T11:00:00.000000Z", "updated_at": "2026-04-15T11:00:00.000000Z"}]}

โ„น๏ธ Alias

GET /api/member/payments

โœ… Empty State (200)

{"success": true, "data": []}

โŒ 403 โ€” Non-member access denied

{"message": "Forbidden"}
GET /api/member/my-payments/{paymentId}/receipt Member-only exact receipt context payload โ–ผ

โœ… Success (200)

{"success": true, "data": {"payment_id": "smp-17", "invoice_number": "SMP-20260415-000017", "member_id": 4, "member_name": "Alice Member", "amount": "1800.00", "plan": "monthly", "payment_mode": "upi", "payment_date": "2026-04-15", "valid_from": "2026-04-15", "valid_to": "2026-05-14", "section_id": 11, "section_name": "AssignFlow", "member_type": "trainer_assigned", "trainer_id": 3, "trainer_name": "John Trainer", "status": "paid", "notes": "legacy section payment", "member_sections": [{"id": 11, "name": "AssignFlow"}, {"id": 3, "name": "Yoga"}], "all_section_names": "AssignFlow, Yoga"}}

โ„น๏ธ paymentId formats

mp-29 | smp-17 | 29

โŒ Not Found (404) โ€” not owned payment

{"success": false, "message": "Payment not found"}
POST /api/gym-admin/member-payments Record member payment (Admin only) - respects custom valid_from/valid_to โ–ผ

โœ… Success (201)

{"success": true, "message": "Payment recorded successfully", "data": {"payment": {"id": 1, "member_id": 4, "amount": "2300.00", "membership_amount": "2000.00", "one_time_registration_fee": "300.00", "total_amount": "2300.00", "apply_registration_fee": true, "plan": "monthly", "payment_mode": "upi", "invoice_number": "MP-20260331-000001", "section_id": 3, "valid_from": "2026-04-01", "valid_to": "2026-05-01", "status": "paid"}, "validity": {"membership_start": "2026-04-01", "membership_expiry": "2026-05-01"}}}

โ„น๏ธ Idempotent Replay (200)

{"success": true, "message": "Payment already recorded (idempotent replay)", "data": {"payment": {"id": 1, "invoice_number": "MP-20260331-000001"}}}
PATCH /api/gym-admin/member-payments/{paymentId} ๐Ÿ†• Update member payment (dates, amount, notes) โ–ผ

โœ… Success (200)

{"success": true, "message": "Payment updated successfully", "data": {"id": 1, "member_id": 4, "amount": "2500.00", "plan": "monthly", "valid_from": "2026-04-15", "valid_to": "2026-05-15", "status": "paid"}}

โŒ 404 โ€” Payment not found or belongs to another gym

{"error": "Not Found"}

โŒ 422 โ€” Date validation error

{"error": {"code": "validation_failed", "message": "Validation failed", "details": {"valid_to": ["The valid_to date must be on or after valid_from."]}}}
DELETE /api/gym-admin/member-payments/{paymentId} ๐Ÿ†• Delete member payment record โ–ผ

โœ… Success (200)

{"success": true, "message": "Payment deleted successfully"}

โŒ 404 โ€” Payment not found or belongs to another gym

{"error": "Not Found"}
GET /api/gym-admin/member-payments List all member payments (includes nullable breakdown fields) โ–ผ
`membership_amount`, `one_time_registration_fee`, `total_amount`, `apply_registration_fee` are always present and may be null for legacy rows.
GET /api/gym-admin/member-payments/dues Overdue members by membership expiry โ–ผ

โœ… Success (200)

{"success": true, "data": [{"id": 4, "member_id": 4, "name": "Bob Martin", "email": "bob@example.com", "membership_expiry": "2026-04-29", "days_overdue": 1, "section_id": 3, "section_name": "Yoga", "membership_plan": "monthly", "status": "inactive"}]}

โœ… Empty (200)

{"success": true, "data": []}
GET /api/gym-admin/member-payments/dues-summary Program-wise overdue member counts โ–ผ

โœ… Success (200)

{"success": true, "data": {"total_dues_members": 2, "programs": [{"section_id": 5, "section_name": "Boxing", "due_members_count": 2}, {"section_id": 3, "section_name": "Yoga", "due_members_count": 1}]}}

โœ… Empty (200)

{"success": true, "data": {"total_dues_members": 0, "programs": []}}
GET /api/gym-admin/member-payments/validity Check membership validity for all members โ–ผ
GET /api/gym-admin/payments/revenue-summary Pre-aggregated monthly revenue across member + section_membership payments (status=paid) for the gym admin's gym โ–ผ
GET /api/receipts/{paymentId}/download Download member payment receipt PDF โ–ผ
๐Ÿ’ผ Trainer Salary Management
PATCH /api/gym-admin/trainers/{trainerId}/salary Define trainer's monthly salary โ–ผ

โœ… Success (200)

{"success": true, "message": "Salary defined successfully", "data": {"trainer": {"id": 3, "trainer_salary": "30000.00"}, "increment_audit": {"id": 1, "old_salary": "25000.00", "new_salary": "30000.00", "increment_amount": "5000.00", "increment_percent": "20.00", "reason": "Annual increment", "effective_date": "2026-04-30"}}}
GET /api/gym-admin/trainers/{id}/salary-history Paginated trainer salary increment audit โ–ผ

โœ… Success (200)

{"success": true, "data": {"data": [{"id": 1, "trainer_id": 3, "old_salary": "25000.00", "new_salary": "30000.00", "increment_amount": "5000.00", "increment_percent": "20.00", "reason": "Annual increment", "effective_date": "2026-04-30", "changed_by": 2}], "current_page": 1, "total": 1}}
GET /api/gym-admin/trainers/{id}/salary-payments Paginated salary payment rows for trainer โ–ผ

โœ… Success (200)

{"success": true, "data": {"data": [{"id": 10, "trainer_id": 3, "amount": "30000.00", "salary_month": "2026-04", "status": "paid"}], "current_page": 1, "total": 1}}
POST /api/gym-admin/trainer-salaries Record monthly salary โ–ผ

โœ… Success (201)

{"success": true, "message": "Salary record created", "data": {"id": 1, "trainer_id": 3, "amount": "25000.00", "salary_month": "2026-03", "status": "paid"}}
PATCH /api/gym-admin/trainer-salaries/{salaryId} Update salary status (paid/hold/reverted) โ–ผ
GET /api/gym-admin/trainer-salaries List all salary records โ–ผ
GET /api/salary-slips/{salaryId}/download Download salary slip PDF โ–ผ
GET /api/trainer/my-members Get members assigned to authenticated trainer โ–ผ
X-User-Id: [trainer_id]

โœ… Success (200)

{
  "success": true,
  "data": [
    {
      "id": 5,
      "name": "Alice Member",
      "email": "alice@example.com",
      "phone": "1234567890",
      "fitness_goal": "Weight Loss",
      "gender": "Female",
      "membership_start": "2025-01-10",
      "membership_expiry": "2025-04-10",
      "membership_plan": "Gold",
      "status": "active",
      "is_active": true
    }
  ]
}
GET /api/trainer/my-salary Get salary records for authenticated trainer with optional filters โ–ผ
X-User-Id: [trainer_id]

โœ… Success (200)

{
  "success": true,
  "data": [
    {
      "id": 15,
      "trainer_id": 3,
      "amount": "50000.00",
      "salary_month": "2025-02",
      "status": "paid",
      "payment_date": "2025-02-05",
      "notes": "Regular salary"
    },
    {
      "id": 14,
      "trainer_id": 3,
      "amount": "50000.00",
      "salary_month": "2025-01",
      "status": "pending",
      "payment_date": null,
      "notes": null
    }
  ]
}
GET /api/gym-admin/trainers/{id}/programs Direct trainer program assignments โ–ผ

โœ… Success (200)

{"success": true, "data": [{"program_id": 11, "program_name": "Yoga", "assignment_id": 9, "status": "active"}]}
POST /api/gym-admin/trainers/{id}/programs/sync Sync trainer program assignments โ–ผ

โ„น๏ธ Use Raw JSON tab

program_ids must be sent as an array, e.g. {"program_ids":[1,2,3]}
GET /api/gym-admin/members/{id}/programs Direct member active program assignments โ–ผ

โœ… Success (200)

{"success": true, "data": [{"program_id": 11, "program_name": "Yoga", "assignment_id": 15, "status": "active", "member_type": "self", "trainer_id": null}]}
POST /api/gym-admin/members/{id}/programs/sync Sync member program assignments โ–ผ

โ„น๏ธ Use Raw JSON tab

program_ids must be sent as an array, e.g. {"program_ids":[1,2,3]}
๐Ÿ“Š Gym Admin Dashboard
GET /api/gym-admin/dashboard Gym admin dashboard overview โ–ผ

โœ… Success (200)

{"success": true, "data": {"members_count": 2, "active_members": 2, "trainers_count": 1, "monthly_earnings": "4000.00", "today_attendance": 3, "monthly_attendance": 45, "total_dues_members": 2, "dues_program_breakdown": [{"section_id": 5, "section_name": "Boxing", "due_members_count": 2}, {"section_id": 3, "section_name": "Yoga", "due_members_count": 1}]}}
๐Ÿท๏ธ Gym Sections / Sports Types Management
๐Ÿ”‘ gym_id & corp_id are automatically set from X-User-Id
You do not pass gym_id in the request body. The server reads the authenticated user's gym from the X-User-Id header and scopes every section to that gym.
Use X-User-Id: 2 (Gym Admin of FitLife Gym โ†’ gym_id=1, corp_id=GYM-DEMO0001) for all section endpoints.
POST /api/gym-admin/sections Create a gym section or sports type (corp-scoped automatically) โ–ผ
๐Ÿ”’ Auto-set from X-User-Id header (e.g. gym_id=1, corp_id=GYM-DEMO0001 for Gym Admin)

โœ… Success (201)

{"success": true, "message": "Section created successfully", "data": {"id": 1, "gym_id": 1, "name": "Non A/C Gym", "type": "gym", "monthly_fee": "500.00", "yearly_fee": "5000.00", "status": "active"}}

โ„น๏ธ SaaS Scope

corp_id is auto-attached from the logged-in gym (no need to pass in request).

๐Ÿ’ก Typical sections to create

โ€ข Non A/C Gym  (type: gym)
โ€ข Premium Gym  (type: gym)
โ€ข Ladies Gym   (type: gym)
โ€ข Badminton    (type: sport)
GET /api/gym-admin/sections List all sections for this gym โ–ผ

โœ… Success (200)

{"success": true, "data": [{"id": 1, "name": "Non A/C Gym", "type": "gym", "monthly_fee": "500.00", "yearly_fee": "5000.00", "status": "active", "active_members_count": 12, "assigned_trainers_count": 2}]}
GET /api/gym-admin/sections/{id} Show a single section โ–ผ

โœ… Success (200)

{"success": true, "data": {"id": 1, "name": "Non A/C Gym", "type": "gym", "monthly_fee": "500.00", "yearly_fee": "5000.00", "status": "active", "active_members_count": 12, "assigned_trainers_count": 2}}
PUT /api/gym-admin/sections/{id} Update section name, fees or type โ–ผ

โœ… Success (200)

{"success": true, "message": "Section updated successfully", "data": {"id": 1, "name": "Non A/C Gym", "monthly_fee": "600.00"}}
PATCH /api/gym-admin/sections/{id}/activate Activate a section โ–ผ
PATCH /api/gym-admin/sections/{id}/deactivate Deactivate a section โ–ผ
DELETE /api/gym-admin/sections/{id} Delete a section (blocked if any members exist) โ–ผ
๐Ÿง‘โ€๐Ÿซ Section Trainers
๐Ÿ”‘ gym_id is auto-scoped from X-User-Id โ€” only trainers belonging to the same gym can be assigned to sections. Use X-User-Id: 2 (Gym Admin).
POST /api/gym-admin/sections/{id}/trainers Assign a trainer to a section โ–ผ

โœ… Success (201)

{"success": true, "message": "Trainer assigned to section", "data": {"id": 1, "section_id": 1, "trainer_id": 3, "status": "active", "trainer": {"id": 3, "name": "John Trainer", "email": "trainer@gym.com"}}}
DELETE /api/gym-admin/sections/{id}/trainers/{trainerId} Remove a trainer from a section โ–ผ
GET /api/gym-admin/sections/{id}/trainers List trainers assigned to a section โ–ผ
GET /api/gym-admin/sections/{id}/members List members enrolled in a section โ–ผ

โœ… Success (200)

{"success": true, "data": {"data": [{"id": 1, "member": {"id": 4, "name": "Alice", "email": "alice@gym.com"}, "trainer": null, "plan": "monthly", "expiry_date": "2026-05-24", "status": "active"}]}}
POST /api/gym-admin/sections/{id}/members Assign one or more members to section (program alias supported) โ–ผ

โœ… Success (201)

{"success":true,"message":"Members assigned to section successfully","data":{"created_memberships":[{"id":12,"section_id":1,"member_id":4,"status":"active"}],"skipped_members":[],"section":{"id":1,"name":"Yoga","members_count":3,"trainers_count":1}}}
DELETE /api/gym-admin/sections/{id}/members/{memberId} Unassign member from section (cancels active membership) โ–ผ
๐Ÿชช Section Memberships
๐Ÿ”‘ gym_id is auto-set from X-User-Id โ€” you do not pass gym_id in the body. The enrollment is automatically scoped to the gym admin's gym.
section_id and member_id must both belong to the same gym. Use X-User-Id: 2 (Gym Admin).
POST /api/gym-admin/section-memberships Enroll a member in a section (trainer-assigned or self) โ–ผ
๐Ÿ”’ Auto-set from X-User-Id header โ€” section & member must belong to the same gym

โœ… Success (201)

{"success": true, "message": "Member enrolled in section successfully", "data": {"id": 1, "section": {"id": 1, "name": "Non A/C Gym", "type": "gym"}, "member": {"id": 4, "name": "Alice"}, "trainer": null, "member_type": "self", "plan": "monthly", "amount": "500.00", "start_date": "2026-04-24", "expiry_date": "2026-05-24", "status": "active"}}

โŒ Already enrolled (422)

{"success": false, "message": "Member is already actively enrolled in this section. Use payment endpoint to extend expiry."}
GET /api/gym-admin/section-memberships List all section memberships with filters โ–ผ
GET /api/gym-admin/section-memberships/expiring Members whose section membership is expiring soon โ–ผ
GET /api/gym-admin/section-memberships/dues Members with expired section memberships (auto-marks them expired) โ–ผ
GET /api/gym-admin/section-memberships/{id} Show a single section membership with payment history โ–ผ
PUT /api/gym-admin/section-memberships/{id} Update membership plan, additive financials, trainer, start or expiry date (alias: /api/gym-admin/memberships/{id}) โ–ผ
Both /section-memberships/{id} and /memberships/{id} use the same update path. Server normalizes then assigns membership + payment fields before dirty-check. Legacy aliases `membership_start` / `membership_expiry` are accepted. 422 is returned only when both assigned models are not dirty. If MEMBERSHIP_SYNC_DEBUG=true, response includes `debug` with before/normalized/dirty/save details. Receipt endpoints reflect saved values immediately.
PATCH /api/gym-admin/section-memberships/{id}/expiry Manual expiry override for section membership โ–ผ
PATCH /api/gym-admin/section-memberships/{id}/cancel Cancel a section membership โ–ผ
PATCH /api/gym-admin/section-memberships/{id}/assign-trainer Assign a trainer to a member's section membership โ–ผ
PATCH /api/gym-admin/section-memberships/{id}/remove-trainer Remove trainer from a membership (switches to self) โ–ผ
๐Ÿ’ฐ Section Membership Payments
๐Ÿ”‘ gym_id is auto-scoped from X-User-Id โ€” the section_membership_id must belong to a membership within the same gym. Use X-User-Id: 2 (Gym Admin).
POST /api/gym-admin/section-membership-payments Record payment & extend section membership expiry โ–ผ
๐Ÿ”’ Auto-set from X-User-Id โ€” payment is scoped to the gym admin's gym

โœ… Success (201)

{"success": true, "message": "Payment recorded. Membership extended to 2026-06-24", "data": {"payment": {"id": 1, "amount": "500.00", "payment_mode": "cash", "plan": "monthly", "valid_from": "2026-05-24", "valid_to": "2026-06-24"}, "membership": {"id": 1, "expiry_date": "2026-06-24", "status": "active"}, "validity": {"base_start": "2026-05-24", "new_expiry": "2026-06-24"}}}
GET /api/gym-admin/section-membership-payments List all section membership payments โ–ผ
GET /api/gym-admin/section-membership-payments/{id} Show a single section payment record โ–ผ
๐ŸŽ‰ Events Module
GET /api/events | /api/member/events | /api/trainer/events Compatibility aliases mapped to upcoming feed logic โ–ผ
GET /api/events/upcoming Public upcoming events (optional gym_id filter) โ–ผ
POST /api/events/{id}/register Public registration (idempotent, cap-enforced) โ–ผ
GET /api/events/my-registrations Returns the authenticated user's event registrations. Requires X-User-Id header. Registrations are linked via user_id stored at registration time. โ–ผ
GET /api/events/payment-config Member-accessible QR config: same shape as admin endpoint; returns null values when no config set โ–ผ
POST /api/events/payments/{paymentRef}/verify Verify online payment and unlock invitation on success โ–ผ
POST /api/events/payments/verify QR automation verify endpoint (member/trainer) โ–ผ
GET /api/events/payments/{paymentRef}/status Poll payment status by payment intent ref โ–ผ
POST /api/events/payments/log Log failed or cancelled payment attempt โ–ผ
GET /api/events/{eventId}/registrations/{registrationId}/payment-status Normalized status for post-UPI auto polling โ–ผ
POST /api/events/{eventId}/registrations/{registrationId}/payments/verify-v2 Idempotent verify by gateway/payment reference โ–ผ
POST /api/events/{eventId}/registrations/{registrationId}/payments/log-failure Log failed/cancelled attempt with reason โ–ผ
POST /api/events/{eventId}/registrations/{registrationId}/payments/submit-proof Member submits UPI transaction reference as payment proof; admin will verify โ–ผ
POST /api/events/{eventId}/registrations/{registrationId}/payments/upload-screenshot Member uploads a payment screenshot as base64 JSON (jpeg/png/webp, max 5 MB decoded); replaces any previous screenshot โ–ผ
GET /api/events/{eventId}/registrations/{registrationId}/payments/screenshot Owner or gym-admin retrieves the stored base64 screenshot and mime type for in-memory rendering โ–ผ
POST /api/events/{eventId}/registrations/{registrationId}/payments/submit-proof Member submits UPI transaction reference as payment proof; admin will verify โ–ผ
POST /api/events/payments/webhook/{provider} Provider callback endpoint (future-safe) โ–ผ
GET /api/events/registrations/{registrationId}/invitation Fetch invitation payload (postponed details included) โ–ผ
GET /api/gym-admin/events Admin event list with year/month/all/date filters โ–ผ
GET /api/gym-admin/events/payment-qr Returns default config (online_payment_enabled=false) when no saved QR config exists โ–ผ
PUT /api/gym-admin/events/payment-qr Update QR config using JSON or multipart file upload (`payment_qr`) โ–ผ

Multipart fields

payment_qr (file): jpg/jpeg/png/webp, max 4MB
online_payment_enabled / is_enabled: true|false|1|0
upi_id: string
instructions: string
remove_qr_image: true|false|1|0

If remove_qr_image=true, previous QR image is deleted and payment_qr_url becomes null.
POST /api/gym-admin/events Create event โ–ผ
PATCH /api/gym-admin/events/{id}/postpone Postpone event with apology message โ–ผ
POST /api/gym-admin/events/{id}/registrations/{registrationId}/payments Record payment โ€” cash, upi, bank_transfer (+ legacy offline/online). Accepts reference_id or payment_reference_id. โ–ผ
๐Ÿƒ Fitness Subscription Payments
POST /api/gym-admin/fitness-subscription-payments Record fitness subscription payment โ–ผ
GET /api/gym-admin/fitness-subscription-payments List fitness subscription payments (paginated) โ–ผ
GET /api/gym-admin/fitness-subscription-payments/{id}/receipt Get fitness subscription payment receipt detail โ–ผ
GET /api/gym-admin/fitness-subscription-payments/{id}/download Download fitness subscription payment receipt PDF โ–ผ
๐Ÿงพ Unified Receipts (All Payment Types)
GET /api/gym-admin/receipts List all receipts (member, section, fitness, gym subscription) with unified filters โ–ผ
GET /api/gym-admin/receipts/{receiptId} Get unified receipt detail (mp-{id}, smp-{id}, fsp-{id}, gp-{id}, ahx-{id}); mp preserves nullable breakdown โ–ผ
GET /api/gym-admin/receipts/{receiptId}/download Download receipt PDF (unified receipt for mp/smp/fsp, gym invoice PDF for gp/ahx) โ–ผ
๐Ÿ“ฑ Flutter v1 / Mobile APIs
GET /api/v1/gym-admin/programs Paginated program list with stable counts โ–ผ
GET /api/v1/gym-admin/programs/{programId}/members Program member assignments with assignment_id โ–ผ
POST /api/v1/gym-admin/programs/{programId}/members Create program member assignment โ–ผ
GET /api/v1/gym-admin/lookup/members Searchable member picker endpoint โ–ผ
GET /api/v1/gym-admin/auth-policy Gym QR/password policy โ–ผ
PUT /api/v1/gym-admin/auth-policy Update gym auth policy โ–ผ
GET /api/v1/gym-admin/qr/live Fetch active rotating QR โ–ผ

โœ… Success (200)

{"success": true, "message": "Live QR fetched successfully", "data": {"qr_session_id": 21, "qr_token": "...", "expires_at": "2026-05-02T11:10:00Z"}}

โŒ Blocked (403 inactive gym)

{"success": false, "message": "Gym is inactive or blocked. Contact Super Admin.", "code": "GYM_INACTIVE", "data": null}
POST /api/v1/gym-admin/qr/refresh Rotate QR session (same active-gym eligibility decision as /qr/live) โ–ผ

โœ… Success (200)

{"success": true, "message": "QR session refreshed successfully", "data": {"qr_session_id": 22, "qr_token": "...", "expires_at": "2026-05-02T11:15:00Z"}}

โŒ Blocked (403 inactive gym)

{"success": false, "message": "Gym is inactive or blocked. Contact Super Admin.", "code": "GYM_INACTIVE", "data": null}
GET /api/v1/mobile/auth/eligibility Public eligibility check with reason codes โ–ผ
POST /api/v1/mobile/auth/qr/scan Validate QR and mark attendance โ–ผ
POST /api/v1/gym-admin/attendance/mark Manual admin attendance entry โ–ผ
GET /api/v1/gym-admin/audit-logs Audit stream for assignment, policy, QR, and attendance changes โ–ผ

GymOps API v1.0 • Built with Laravel • Multi-Tenant SaaS Gym Management

Seed Users: Super Admin (ID: 1) • Gym Admin (ID: 2) • Trainer (ID: 3) • Member Alice (ID: 4) • Member Bob (ID: 5)