Back to landing page
Last updated: 09 Jul 2026, 10:15 AM
Documentation

App API Flow

React Native app API routes, payloads, responses, and notes.

App Portal API Flow

This document is for the mobile/app developer integrating the app portal APIs.

Base URL

{API_BASE_URL}/api/app

Example local URL:

http://127.0.0.1:8000/api/app

For authenticated APIs, send the Sanctum token as:

Authorization: Bearer {access_token}
Accept: application/json

Main Registration Flow

  1. Fetch app versions and enforce update behavior if needed.
  2. Send signup OTP to email using /auth/signup/send/otp.
  3. Verify email OTP using /auth/signup/verify/otp.
  4. Send signup OTP to phone number using /auth/signup/send/otp.
  5. Verify phone OTP using /auth/signup/verify/otp.
  6. Complete signup using /auth/signup/verify.
  7. Fetch master data for business form.
  8. Save business details using the temporary business-details token.
  9. Store the returned app token for normal app usage.
  10. Register the active device token using /notifications/device-token.
  11. Fetch available chapters.
  12. Submit the selected member chapter.
  13. Use notification settings APIs for app settings toggles.
  14. Use notification inbox APIs for notification listing and read state.
  15. Use member listing API for the members tab.
  16. If selected member type is app-admin, use add-member API from the members tab.
  17. Use member details API when opening a member profile from the members tab.
  18. If selected member type is app-admin, use member profile update API to edit another member's profile.
  19. If selected member type is app-admin, use member business update API to edit another member's business details.
  20. Use business listing and business details APIs for the business directory.
  21. Use profile APIs for current profile, edit personal details, and change password.
  22. Use 1:1 session APIs for member meeting entries.
  23. Use referral APIs for referral entries.
  24. Use event APIs for event listing, event detail, attendance marking, app-admin attendance submission, and event photo gallery/upload.
  25. Use contact-us details API for the Contact Us screen.
  26. Use grievance APIs for the Grievance screen.
  27. Use home APIs for dashboard widgets such as current-month birthdays.

Home APIs

These APIs back the app home page widgets.

Current Month Birthdays

GET /home/birthdays
Authorization: Bearer {app_access_token}

Behavior:

  • Returns approved members from all chapters.
  • Includes members whose date_of_birth month matches the current server month.
  • Sorted by birth day within the month.

Success response:

{
  "message": "Birthdays found.",
  "total_birthdays": 2,
  "month": 5,
  "data": [
    {
      "id": "member_uuid",
      "name": "Amit Shah",
      "date_of_birth": "1990-05-05",
      "profile_image": "member-profiles/amit.jpg",
      "profile_image_url": "https://cdn.example.com/member-profiles/amit.jpg"
    }
  ]
}

When no birthdays are found, message is Birthdays not found., total_birthdays is 0, and data is an empty array.

Upcoming Events

GET /home/upcoming-events?member_chapter_id={member_chapter_id}
Authorization: Bearer {app_access_token}

Behavior:

  • Requires the currently selected member chapter. It can also be sent as X-Member-Chapter-Id.
  • Returns events for the selected chapter plus events with visibility_scope = ALL.
  • Events belonging only to another/previously selected chapter are excluded.
  • Returns events with event_date greater than or equal to the current server date.
  • Excludes CANCELLED and COMPLETED events.
  • Sorted by event date and start time.
  • Limited to 10 records.

Success response:

{
  "message": "Upcoming events found.",
  "total_upcoming_events": 10,
  "data": [
    {
      "id": "event_uuid",
      "event_type_id": "event_type_uuid",
      "event_type": {
        "id": "event_type_uuid",
        "code": "EVENT",
        "name": "Event"
      },
      "title": "Business Growth Workshop",
      "description": "Workshop description",
      "event_date": "2026-06-05",
      "start_time": "10:00",
      "end_time": "13:00",
      "location_name": "Ahmedabad Convention Center",
      "visible_to": "All Members",
      "banner_image": "event-banners/workshop.jpg",
      "banner_image_url": "https://cdn.example.com/event-banners/workshop.jpg",
      "status": "ACTIVE",
      "is_attended": false,
      "total_attendees": 0,
      "total_photos": 0
    }
  ]
}

When no events are found, message is Upcoming events not found., total_upcoming_events is 0, and data is an empty array.

Home Counters

GET /home/counters?member_chapter_id={member_chapter_id}
Authorization: Bearer {app_access_token}

The selected member chapter is required. It can be sent as member_chapter_id or X-Member-Chapter-Id.

Behavior:

  • The API uses the selected member chapter to decide whether the logged-in app user is in member mode or app-admin mode.
  • Normal member response keys:
    • one_to_one_sessions
    • points_earned
    • referral_taken
    • referral_given
    • event_attended
    • attendance
    • total_business_exchange
  • App-admin response keys:
    • total_members
    • total_referrals
    • total_business_exchange
    • earnings
    • points_earned
    • events
    • attendance
  • points_earned: returns active, non-expired point ledger total as a formatted decimal string.
  • attendance: returns a percentage string with two decimal places.
  • Normal member formula: (member's PRESENT event attendance / total events visible to the selected chapter) × 100.
  • App-admin formula: (eligible PRESENT attendance records / eligible member-event opportunities) × 100.
  • App-admin visible events include events created for the selected chapter and events whose visibility is ALL.
  • An event contributes one denominator opportunity for each selected-chapter member whose date_of_joining is on or before the event date. Members without a joining date are treated as eligible for backward compatibility.
  • A PRESENT record is included in the app-admin numerator only when that member was eligible for that event.
  • When there are no visible events, attendance is 0.00%.
  • For normal members, counts are selected-chapter scoped.
  • For app-admin:
    • total_business_exchange is overall across all chapters.
    • earnings is only for the selected chapter.
    • points_earned is the active point total for the selected chapter.

Member success response:

{
  "message": "Home counters found.",
  "data": {
    "one_to_one_sessions": 4,
    "points_earned": "120.00",
    "referral_taken": 3,
    "referral_given": 5,
    "event_attended": 2,
    "attendance": "50.00%",
    "total_business_exchange": "25000.00"
  }
}

App-admin success response:

{
  "message": "Home counters found.",
  "data": {
    "total_members": 128,
    "total_referrals": 842,
    "total_business_exchange": "45000.00",
    "earnings": "1250000.00",
    "points_earned": "4850.00",
    "events": 12,
    "attendance": "40.00%"
  }
}

Member Points

Points are stored in member_point_ledgers and are not calculated only from live module counts. Every earning event writes one ledger row with both point_type_id and point_rule_id, which prevents duplicate awards for the same member, point type, and source record while preserving the exact rule used.

Current point rules:

Rule Trigger Points
EVENT_ATTENDED Event attendance marked PRESENT 20
TIME_PUNCTUALITY Attendance marked within 15 minutes of event start 10
BUSINESS_EXCHANGE Business exchange created 1% of business amount
MEMBER_REFERRAL Referral created 50
ONE_TO_ONE_SESSION 1:1 session created 20 per participant

Ledger behavior:

  • financial_year_id is resolved automatically from earned_at.
  • Current financial year is April 1 to March 31.
  • expired_at is calculated from the current point_rules row for that point type. Current seeded rules expire at financial year end.
  • Dashboard totals include only earned, non-expired ledger rows.
  • Business exchange points are awarded to the referred-by member.
  • Referral points are awarded to the referring-by member.

Chapter Activity

GET /home/activity?member_chapter_id={member_chapter_id}
Authorization: Bearer {app_access_token}

The selected member chapter is required. It can be sent as member_chapter_id or X-Member-Chapter-Id.

Behavior:

  • Returns activity for the logged-in selected chapter.
  • Activity is created when members create:
    • 1:1 session
    • Referral
    • Business exchange
  • Default limit is 10 records. Optional limit is accepted from 1 to 50.
  • Sorted by latest activity first.
  • For the home preview, call without page and without view.
  • For View All listing, send view=LIST&page=1&limit=10. This returns meta and groups activity under date headers.

Success response:

{
  "message": "Chapter activities found.",
  "total_activities": 3,
  "data": [
    {
      "id": "activity_uuid",
      "activity_type": "BUSINESS_EXCHANGE",
      "title": "Amit Shah recorded business exchange with Neha Patel",
      "time_ago": "2 hours ago",
      "activity_at": "2026-05-25T10:00:00.000000Z",
      "source_type": "BusinessExchange",
      "source_id": "business_exchange_uuid",
      "amount": "18000.00"
    }
  ]
}

When no activity is found, message is Chapter activities not found., total_activities is 0, and data is an empty array.

View All request:

GET /home/activity?member_chapter_id={member_chapter_id}&view=LIST&page=1&limit=10
Authorization: Bearer {app_access_token}

View All response:

{
  "message": "Chapter activities found.",
  "total_activities": 25,
  "meta": {
    "total_records": 25,
    "page": 1,
    "limit": 10,
    "total_pages": 3,
    "record_start": 1,
    "record_end": 10
  },
  "data": [
    {
      "date_label": "Today",
      "date": "2026-05-26",
      "activities": [
        {
          "id": "activity_uuid",
          "activity_type": "REFERRAL",
          "title": "Amit Shah sent referral to Neha Patel",
          "time_ago": "2 hours ago",
          "activity_at": "2026-05-26T10:00:00.000000Z",
          "source_type": "Referral",
          "source_id": "referral_uuid",
          "amount": null
        }
      ]
    },
    {
      "date_label": "Yesterday",
      "date": "2026-05-25",
      "activities": []
    }
  ]
}

Forgot Password Flow

  1. Send forgot-password OTP to the member email or phone number.
  2. Verify the OTP.
  3. Store the returned temporary reset_token.
  4. Create the new password using the reset_token.
  5. Ask the user to log in again with the new password.

Member APIs

These APIs back the members tab in the app portal.

Every member API must receive the selected member chapter. Send it as member_chapter_id in the query/body, or as the X-Member-Chapter-Id header.

The API decides the screen mode from the selected member chapter's member_type:

  • MEMBER: member mode.
  • Any other member type: app-admin mode.

Important: app-admin here means a logged-in app member whose selected member_type is not MEMBER. It does not use the admin portal /api/admin route and does not depend on users.type = ADMIN.

List Members

GET /members

Default behavior:

  • Returns members from all chapters by default.
  • Returns only members whose approval status is APPROVED.
  • Excludes the logged-in member.
  • Returns can_add_member: true only in app-admin mode.
  • Send chapter_id only when you want chapter-specific filtering.

Examples:

GET /members?member_chapter_id={member_chapter_id}
GET /members?member_chapter_id={member_chapter_id}&search=Acme
GET /members?member_chapter_id={member_chapter_id}&chapter_id={chapter_id}
GET /members?member_chapter_id={member_chapter_id}&business_category_id={category_id}&city_id={city_id}

Query params:

Query param Required Notes
member_chapter_id Yes Selected member chapter. Can be sent as X-Member-Chapter-Id header instead.
search No Searches member number, member name, member email, phone, whatsapp, business name, business contact fields, business address, and chapter name.
q No Alias for search.
chapter_id No Filters members by a specific active chapter. By default, the API returns all chapters.
member_type_id No Filters members by assigned member type.
business_category_id No Filters by member business category.
business_sub_category_id No Filters by member business sub category.
country_id No Filters by member business country.
state_id No Filters by member business state.
city_id No Filters by member business city.

Success response:

{
  "message": "Members found.",
  "can_add_member": true,
  "total_members": 1,
  "selected_chapter": {
    "member_chapter_id": "uuid",
    "chapter_id": "uuid",
    "date_of_joining": "2026-05-27",
    "name": "Ahmedabad Chapter",
    "description": "Description",
    "member_type": {
      "id": "uuid",
      "code": "CHAPTER_ADMIN",
      "name": "Chapter Admin"
    }
  },
  "data": [
    {
      "id": "uuid",
      "member_number": "BCI000001",
      "name": "Robert Fox",
      "email": "robert@example.com",
      "phone_number": "9876543210",
      "profile_image": "member-profiles/photo.jpg",
      "profile_image_url": "https://cdn.example.com/member-profiles/photo.jpg",
      "business_name": "Stellar Real Estate Group"
    }
  ]
}

When no records are found, message is Members not found., total_members is 0, and data is an empty array.

Member Details

GET /members/details
Authorization: Bearer {app_access_token}

Use this when opening a member profile from the members tab.

Examples:

GET /members/details?member_chapter_id={member_chapter_id}&member_id={member_id}
GET /members/details?member_chapter_id={member_chapter_id}&id={member_id}

Query params:

Query param Required Notes
member_chapter_id Yes Selected member chapter. Can be sent as X-Member-Chapter-Id header instead.
member_id Yes Member id from list API. Alias: id.
chapter_id No Filters by a specific active chapter. By default, the API checks across all chapters.

Success response:

{
  "message": "Member found.",
  "selected_chapter": {
    "member_chapter_id": "uuid",
    "chapter_id": "uuid",
    "name": "Ahmedabad Chapter",
    "description": "Description",
    "member_type": {
      "id": "uuid",
      "code": "CHAPTER_ADMIN",
      "name": "Chapter Admin"
    }
  },
  "data": {
    "id": "uuid",
    "member_number": "BCI000001",
    "name": "Robert Fox",
    "email": "robert@example.com",
    "phone_number": "9876543210",
    "date_of_birth": "1992-01-15",
    "whatsapp": "9876543210",
    "profile_image": "member-profiles/photo.jpg",
    "business": {},
    "member_chapters": [
      {
        "member_chapter_id": "uuid",
        "chapter_id": "uuid",
        "date_of_joining": "2026-05-27",
        "chapter": {
          "id": "uuid",
          "name": "Ahmedabad Chapter",
          "description": "Description"
        },
        "member_type": {
          "id": "uuid",
          "code": "MEMBER",
          "name": "Member"
        }
      }
    ]
  }
}

If the member does not exist, the API returns 404 with Member was not found.

App Admin: Add Member

POST /members/store
Content-Type: multipart/form-data

This API is available only in app-admin mode. A normal member receives 403 Forbidden.

The backend creates:

  • users row with type = MEMBER.
  • members profile row.
  • member_businesses row.
  • member_chapters row with member type MEMBER.
  • NEW_MEMBER_JOINED notification for the other approved members and admins of the assigned chapter.

OTP verification is not required because the member is created by an app admin.

The notification excludes the newly created member and the creator/action taker.

Request fields:

Field Required Notes
member_chapter_id Yes Selected app-admin member chapter. Can be sent as X-Member-Chapter-Id header instead.
name Yes Member name.
email Yes Must be unique in users.
phone_number Yes Must be unique in users.
password No Minimum 8 characters. Defaults to password if not sent.
date_of_birth No Date.
whatsapp No String, max 30.
profile_photo No JPG/JPEG/PNG image, max 10 MB. Alias: profile_image.
chapter_id Yes Chapter assigned to the new member.
date_of_joining No Joining date stored on the created member chapter. Format: YYYY-MM-DD. Defaults to the current server date when omitted.
business.business_category_id Yes Must exist in business categories.
business.business_sub_category_id Yes Must exist in business categories.
business.country_id Yes Must exist in countries.
business.state_id Yes Must exist in states.
business.city_id Yes Must exist in cities.
business.name Yes Business name.
business.gst_number No GST number.
business.mobile_number No Business mobile number. Defaults from member phone number when empty.
business.whatsapp_number No Business whatsapp number. Defaults from member whatsapp/phone number when empty.
business.email No Business email. Defaults from member email when empty.
business.website No Business website URL.
business.description No Business description.
business.full_address No Business full address.
business.business_logo No JPG/JPEG/PNG/WEBP image, max 2 MB. Aliases: business_logo, logo, business_logo_image.
business.business_images[] No JPG/JPEG/PNG/WEBP images, max 10 MB each. Maximum 6 active business images. Aliases: business_images[], photos[].

JSON request example:

{
  "member_chapter_id": "uuid",
  "name": "Robert Fox",
  "date_of_birth": "1992-01-15",
  "email": "robert@example.com",
  "phone_number": "9876543210",
  "whatsapp": "9876543210",
  "password": "password123",
  "chapter_id": "uuid",
  "date_of_joining": "2026-05-27",
  "business": {
    "business_category_id": "uuid",
    "business_sub_category_id": "uuid",
    "country_id": "uuid",
    "state_id": "uuid",
    "city_id": "uuid",
    "name": "Stellar Real Estate Group",
    "gst_number": "24ABCDE1234F1Z5",
    "mobile_number": "9876543210",
    "whatsapp_number": "9876543210",
    "email": "business@example.com",
    "website": "https://example.com",
    "description": "Business description",
    "full_address": "Full business address"
  }
}

For multipart/form-data, send nested business fields as business[name], business[email], business[business_logo], business[business_images][], etc. Flat aliases such as business_name, business_email, business_mobile_number, business_full_address, gst_number, country_id, state_id, city_id, business_logo, and business_images[] are also accepted.

Success response:

{
  "message": "Member created successfully."
}

Common errors:

{
  "message": "This action is only available for app admins."
}
{
  "message": "Email is already registered with another account. (and 1 more error)",
  "errors": {
    "email": [
      "Email is already registered with another account."
    ],
    "phone_number": [
      "Phone number is already registered with another account."
    ]
  }
}

App Admin: Update Member Profile

POST /members/update
Authorization: Bearer {app_access_token}
Content-Type: multipart/form-data

This API is available only in app-admin mode. A normal member receives 403 Forbidden.

Use this when an app admin edits another member's personal profile from the members tab. For the logged-in user's own profile, continue using /profile/update.

Request fields:

Field Required Notes
member_chapter_id Yes Selected app-admin member chapter. Can be sent as X-Member-Chapter-Id header instead.
member_id Yes Member profile to update. Alias: id.
name Yes Member name. Alias: full_name.
email Yes Must be unique in users, ignoring the edited member's current user.
phone_number Yes Must be unique in users, ignoring the edited member's current user. Alias: mobile_number.
date_of_birth No Date.
whatsapp No String, max 30.
profile_photo No JPG/JPEG/PNG image, max 2 MB. Alias: profile_image.

Request example:

{
  "member_chapter_id": "uuid",
  "member_id": "uuid",
  "full_name": "Rahul Sharma",
  "date_of_birth": "1992-01-15",
  "mobile_number": "912345678901",
  "email": "rahul@example.com",
  "whatsapp": "912345678900"
}

Success response:

{
  "message": "Member profile updated successfully.",
  "data": {
    "id": "member_uuid",
    "name": "Rahul Sharma",
    "email": "rahul@example.com",
    "phone_number": "912345678901",
    "member_number": "BCI000001",
    "date_of_birth": "1992-01-15",
    "whatsapp": "912345678900",
    "profile_image": "member-profiles/photo.jpg",
    "profile_image_url": "https://cdn.example.com/member-profiles/photo.jpg",
    "business": {},
    "member_chapters": [
      {
        "member_chapter_id": "uuid",
        "chapter_id": "uuid",
        "date_of_joining": "2026-05-27",
        "chapter": {
          "id": "uuid",
          "name": "Ahmedabad Chapter",
          "description": "Description"
        },
        "member_type": {
          "id": "uuid",
          "code": "MEMBER",
          "name": "Member"
        }
      }
    ]
  }
}

Business Directory APIs

These APIs back the business listing and business details screens in the app portal.

Every business directory API must receive the selected member chapter. Send it as member_chapter_id in the query/body, or as the X-Member-Chapter-Id header.

Default visibility:

  • Returns businesses from all chapters by default.
  • Send chapter_id to filter a specific active chapter.

List Businesses

GET /business

Only businesses belonging to members whose approval status is APPROVED are returned.

Examples:

GET /business?member_chapter_id={member_chapter_id}
GET /business?member_chapter_id={member_chapter_id}&search=software
GET /business?member_chapter_id={member_chapter_id}&business_category_id={category_id}

Query params:

Query param Required Notes
member_chapter_id Yes Selected member chapter. Can be sent as X-Member-Chapter-Id header instead.
search No Searches business name, contact fields, address, category, location, owner member fields, and chapter name.
q No Alias for search.
chapter_id No Filters businesses by a specific active chapter. By default, the API returns all chapters.
business_category_id No Filters by business category.
business_sub_category_id No Filters by business sub category.
country_id No Filters by business country.
state_id No Filters by business state.
city_id No Filters by business city.

Success response:

{
  "message": "Businesses found.",
  "total_businesses": 1,
  "data": [
    {
      "id": "business_uuid",
      "member_id": "member_uuid",
      "name": "Stellar Real Estate Group",
      "mobile_number": "9876543210",
      "whatsapp_number": "9876543210",
      "email": "business@example.com",
      "website": "https://example.com",
      "full_address": "Full business address",
      "business_category_name": "Real Estate",
      "business_sub_category_name": "Residential",
      "member_name": "Robert Fox"
    }
  ]
}

When no records are found, message is Businesses not found., total_businesses is 0, and data is an empty array.

Business Details

GET /business/details

Example:

GET /business/details?business_id={business_id}&member_chapter_id={member_chapter_id}

Query params:

Query param Required Notes
business_id Yes Business id from list API.
member_chapter_id Yes Selected member chapter. Can be sent as X-Member-Chapter-Id header instead.
chapter_id No Filters by a specific active chapter. By default, the API checks across all chapters.

Success response:

{
  "message": "Business found.",
  "data": {
    "id": "business_uuid",
    "member_id": "member_uuid",
    "name": "Stellar Real Estate Group",
    "gst_number": "24ABCDE1234F1Z5",
    "mobile_number": "9876543210",
    "whatsapp_number": "9876543210",
    "email": "business@example.com",
    "website": "https://example.com",
    "description": "Business description",
    "full_address": "Full business address",
    "business_logo": "business-logos/business_uuid/logo.png",
    "business_logo_url": "https://cdn.example.com/business-logos/business_uuid/logo.png",
    "business_category": {},
    "business_sub_category": {},
    "country": {},
    "state": {},
    "city": {},
    "member": {},
    "images": [
      {
        "id": "uuid",
        "business_id": "business_uuid",
        "image_path": "business-images/business_uuid/photo.jpg",
        "image_url": "https://cdn.example.com/business-images/business_uuid/photo.jpg",
        "caption": null,
        "sort_order": 1,
        "created_at": "2026-05-23T09:30:00.000000Z"
      }
    ]
  }
}

If the business does not exist, the API returns 404 with Business was not found.

App Admin: Update Member Business Details

POST /business/update
Authorization: Bearer {app_access_token}
Content-Type: multipart/form-data

This API is available only in app-admin mode. A normal member receives 403 Forbidden.

Use this when an app admin edits another member's business details. If the selected member does not yet have business details, the backend creates them.

Request:

{
  "member_chapter_id": "uuid",
  "member_id": "uuid",
  "business_category_id": "uuid",
  "business_sub_category_id": "uuid",
  "country_id": "uuid",
  "state_id": "uuid",
  "city_id": "uuid",
  "name": "Updated Business Name",
  "gst_number": "24ABCDE1234F1Z5",
  "mobile_number": "9123456789",
  "whatsapp_number": "9123456789",
  "email": "updated-business@example.com",
  "website": "https://updated.example.com",
  "description": "Updated business description",
  "full_address": "Updated Ahmedabad address",
  "business_logo": "business-logos/business_uuid/logo.png",
  "delete_business_image_ids": ["uuid"]
}

For business photos, send multipart/form-data:

  • business_logo: JPG/JPEG/PNG/WEBP image, max 2 MB.
  • Alias: logo or business_logo_image.
  • business_images[]: JPG/JPEG/PNG/WEBP images, max 10 MB each.
  • Alias: photos[].
  • Max total images per business: 6.
  • delete_business_image_ids[]: existing business image ids to remove.
  • Alias: deleted_image_ids[].

Validation:

Field Required Notes
member_chapter_id Yes Selected app-admin member chapter. Can be sent as X-Member-Chapter-Id header instead.
member_id Yes Member whose business details should be updated. Alias: id.
business_category_id Yes Must exist in business categories.
business_sub_category_id Yes Must exist in business categories.
country_id Yes Must exist in countries.
state_id Yes Must exist in states.
city_id Yes Must exist in cities.
name Yes Business name.
gst_number Yes GST number.
mobile_number Yes Business mobile number.
whatsapp_number Yes Business whatsapp number.
email Yes Business email.
website Yes Business website URL.
description Yes Business description.
full_address Yes Business full address.
business_logo No JPG/JPEG/PNG/WEBP image, max 2 MB. Alias: logo or business_logo_image.
business_images[] No JPG/JPEG/PNG/WEBP images, max 10 MB each. Alias: photos[].
delete_business_image_ids[] No Existing business image ids to delete. Alias: deleted_image_ids[].

Success response:

{
  "message": "Member business details updated successfully.",
  "data": {
    "id": "business_uuid",
    "member_id": "member_uuid",
    "business_category_id": "uuid",
    "business_sub_category_id": "uuid",
    "country_id": "uuid",
    "state_id": "uuid",
    "city_id": "uuid",
    "name": "Updated Business Name",
    "gst_number": "24ABCDE1234F1Z5",
    "mobile_number": "9123456789",
    "whatsapp_number": "9123456789",
    "email": "updated-business@example.com",
    "website": "https://updated.example.com",
    "description": "Updated business description",
    "full_address": "Updated Ahmedabad address",
    "business_logo": "business-logos/business_uuid/logo.png",
    "business_logo_url": "https://cdn.example.com/business-logos/business_uuid/logo.png",
    "business_category": {
      "id": "uuid",
      "name": "Technology"
    },
    "business_sub_category": {
      "id": "uuid",
      "name": "Software Development"
    },
    "country": {
      "id": "uuid",
      "name": "India"
    },
    "state": {
      "id": "uuid",
      "name": "Gujarat"
    },
    "city": {
      "id": "uuid",
      "name": "Ahmedabad"
    },
    "images": []
  }
}

1:1 Session APIs

These APIs back both 1:1 session screens from the app portal.

Every 1:1 session API must receive the selected member chapter. Send it as member_chapter_id in the query/body, or as the X-Member-Chapter-Id header.

The API decides the screen mode from the selected member chapter's member_type:

  • MEMBER: member mode.
  • Any other member type: app-admin mode.

Member: Member Options

Use this for the "Person you met" dropdown. The logged-in member is excluded.

GET /one-to-one-sessions/member-options

Success response:

{
  "message": "Members found.",
  "data": [
    {
      "id": "uuid",
      "member_number": "BCI000001",
      "name": "Alfonso Dias",
      "email": "alfonso@example.com",
      "phone_number": "9876543210",
      "business": {
        "id": "uuid",
        "name": "Alfonso Dias Business"
      }
    }
  ]
}

Member: List 1:1 Sessions

GET /one-to-one-sessions

Returns sessions where the logged-in member is either the creator member or the person met.

Example:

GET /one-to-one-sessions?member_chapter_id={member_chapter_id}

Member: Create 1:1 Session

POST /one-to-one-sessions/store

Request:

{
  "member_chapter_id": "uuid",
  "person_you_met_member_id": "uuid",
  "visit_date": "2026-05-13",
  "remarks": "Discussed specific requirement and opportunity."
}

session_with_member_id is also accepted instead of person_you_met_member_id.

Validation:

Field Required Notes
member_chapter_id Yes Selected member chapter. Can be sent as X-Member-Chapter-Id header instead.
person_you_met_member_id Yes Must be an existing member from the selected chapter. Use session_with_member_id if preferred by the app code.
visit_date Yes Date string, for example 2026-05-13.
remarks Yes Meeting remarks.

Success response:

{
  "message": "1:1 session created successfully.",
  "data": {
    "id": "uuid",
    "chapter_id": "uuid",
    "member_id": "uuid",
    "session_with_member_id": "uuid",
    "visit_date": "2026-05-13",
    "remarks": "Discussed specific requirement and opportunity.",
    "member": {},
    "session_with_member": {},
    "created_at": "2026-05-13T10:00:00.000000Z",
    "updated_at": "2026-05-13T10:00:00.000000Z"
  }
}

Notes:

  • The created 1:1 session stores the selected chapter as chapter_id.
  • Both members must belong to the selected chapter.

App Admin: Member Options

GET /one-to-one-sessions/member-options

In app-admin mode, this returns members from the selected chapter so the first dropdown can select the main member.

Example:

GET /one-to-one-sessions/member-options?member_chapter_id={member_chapter_id}

App Admin: List 1:1 Sessions

GET /one-to-one-sessions

Optional filter:

GET /one-to-one-sessions?member_id={member_id}

Include member_chapter_id in the query or X-Member-Chapter-Id header.

App Admin: Create 1:1 Session

POST /one-to-one-sessions/store

Request:

{
  "member_chapter_id": "uuid",
  "member_id": "uuid",
  "session_with_member_id": "uuid",
  "visit_date": "2026-05-14",
  "remarks": "Initial discussion."
}

Validation:

Field Required Notes
member_chapter_id Yes Selected app-admin member chapter. Can be sent as X-Member-Chapter-Id header instead.
member_id Yes Main member selected by the app admin screen.
session_with_member_id Yes Other member in the session. Must be different from member_id.
visit_date Yes Date string, for example 2026-05-14.
remarks No Meeting remarks.

Grievance APIs

These APIs back the Grievance screen in the app portal.

Every grievance API must receive the selected member chapter. Send it as member_chapter_id in the query/body, or as the X-Member-Chapter-Id header.

Reported Member/Admin Options

Use this for the reported person search field. For the Admin complaint type, send complaint_type_code=ADMIN to return members assigned to non-MEMBER member types.

GET /grievances/reported-member-options?member_chapter_id={member_chapter_id}&complaint_type_code=ADMIN&search=Sarah
Authorization: Bearer {app_access_token}

Query params:

Query param Required Notes
member_chapter_id Yes Selected member chapter. Can be sent as X-Member-Chapter-Id header instead.
complaint_type_code No Send ADMIN to filter options to app/chapter admins. Alias: type.
search No Searches member number, name, email, and phone number. Alias: q.

Success response:

{
  "message": "Members found.",
  "data": [
    {
      "id": "uuid",
      "member_number": "BCI000001",
      "name": "Sarah Admin",
      "email": "sarah@example.com",
      "phone_number": "9876543210"
    }
  ]
}

Submit Grievance

POST /grievances/store
Authorization: Bearer {app_access_token}

Request:

{
  "member_chapter_id": "uuid",
  "complaint_type_id": "uuid",
  "reported_member_id": "uuid",
  "issue": "During the regional meetup on Friday, the member repeatedly interrupted presentations and used offensive language when corrected."
}

Validation:

Field Required Notes
member_chapter_id Yes Selected member chapter. Can be sent as X-Member-Chapter-Id header instead.
complaint_type_id Yes Must be an active complaint type from /masters/complaint-types.
reported_member_id No Member/admin being reported. Aliases: reported_admin_id, reported_user_id, report_against_member_id.
issue Yes Grievance issue/details. Aliases: description, message, details, complaint_details.
subject No Optional short subject. If not sent, the backend derives it from the issue text. Alias: title.

Success response:

{
  "message": "Grievance submitted successfully.",
  "data": {
    "id": "uuid",
    "member_id": "uuid",
    "member_chapter_id": "uuid",
    "complaint_type_id": "uuid",
    "complaint_type": {
      "id": "uuid",
      "code": "ADMIN",
      "name": "Admin"
    },
    "reported_member_id": "uuid",
    "reported_member": {
      "id": "uuid",
      "member_number": "BCI000001",
      "name": "Sarah Admin",
      "email": "sarah@example.com",
      "phone_number": "9876543210"
    },
    "subject": "During the regional meetup on Friday, the member repeatedly interrupted presentations",
    "description": "During the regional meetup on Friday, the member repeatedly interrupted presentations and used offensive language when corrected.",
    "status": "OPEN",
    "created_at": "2026-05-22T10:00:00.000000Z",
    "updated_at": "2026-05-22T10:00:00.000000Z"
  }
}

Referral APIs

These APIs back both referral screens from the app portal.

Every referral API must receive the selected member chapter. Send it as member_chapter_id in the query/body, or as the X-Member-Chapter-Id header.

The API decides the screen mode from the selected member chapter's member_type:

  • MEMBER: member mode.
  • Any other member type: app-admin mode.

Member: Member Options

Use this for the "Referring To" dropdown. The logged-in member is excluded.

GET /referrals/member-options

Member: List Referrals

GET /referrals

Returns referrals from the selected chapter where the logged-in member is either the referring-by member or the referring-to BCI member.

Examples:

GET /referrals?member_chapter_id={member_chapter_id}
GET /referrals?member_chapter_id={member_chapter_id}&referral_direction=SENT
GET /referrals?member_chapter_id={member_chapter_id}&referral_direction=RECEIVED
GET /referrals?member_chapter_id={member_chapter_id}&search=Rahul&from_date=2026-04-01&to_date=2026-04-30

Member listing filters:

Query param Required Notes
member_chapter_id Yes Selected member chapter. Can be sent as X-Member-Chapter-Id header instead.
referral_direction No Use uppercase values: SENT shows referrals given by the logged-in member. RECEIVED shows referrals received by the logged-in member.
type No Backward-compatible alias for referral_direction. Prefer referral_direction in new app code.
search No Searches referring person, referral details, referring-by member name, referring-to member name, and exact created date.
q No Alias for search.
member_name No Filters by referring-by or referring-to member name.
from_date No Created date lower bound, for example 2026-04-01.
to_date No Created date upper bound, for example 2026-04-30.
date_from No Alias for from_date.
date_to No Alias for to_date.

List response:

{
  "message": "Referrals found.",
  "total_referrals": 124,
  "data": [
    {
      "id": "uuid",
      "chapter_id": "uuid",
      "referring_by_member_id": "uuid",
      "referring_to_member_id": "uuid",
      "referring_person": "Ravi Shah",
      "referral_details": "Needs business automation consultation.",
      "contact_number": "9876543210",
      "email": "ravi@example.com",
      "referring_by_member": {},
      "referring_to_member": {},
      "created_at": "2026-05-14T10:00:00.000000Z",
      "updated_at": "2026-05-14T10:00:00.000000Z"
    }
  ]
}

Member: Create Referral

POST /referrals/store

Request:

{
  "member_chapter_id": "uuid",
  "referring_to_member_id": "uuid",
  "referring_person": "Ravi Shah",
  "referral_details": "Needs business automation consultation.",
  "contact_number": "9876543210",
  "email": "ravi@example.com"
}

Validation:

Field Required Notes
member_chapter_id Yes Selected member chapter. Can be sent as X-Member-Chapter-Id header instead.
referring_to_member_id Yes Must be an existing member from the selected chapter and different from the logged-in member.
referring_person Yes Person being referred.
referral_details Yes Specific requirement, opportunity, or service needed.
contact_number Yes Contact number for the referred person.
email Yes Email for the referred person.

Success response:

{
  "message": "Referral created successfully.",
  "data": {
    "id": "uuid",
    "chapter_id": "uuid",
    "referring_by_member_id": "uuid",
    "referring_to_member_id": "uuid",
    "referring_person": "Ravi Shah",
    "referral_details": "Needs business automation consultation.",
    "contact_number": "9876543210",
    "email": "ravi@example.com",
    "referring_by_member": {},
    "referring_to_member": {},
    "created_at": "2026-05-14T10:00:00.000000Z",
    "updated_at": "2026-05-14T10:00:00.000000Z"
  }
}

Notes:

  • The created referral stores the selected chapter as chapter_id.
  • Both members must belong to the selected chapter.

App Admin: Member Options

GET /referrals/member-options

In app-admin mode, this returns members from the selected chapter so the "Referring By" and "Referring To" dropdowns can use the same options.

App Admin: List Referrals

GET /referrals

Optional filter:

GET /referrals?member_id={member_id}

Include member_chapter_id in the query or X-Member-Chapter-Id header.

Examples:

GET /referrals?member_chapter_id={member_chapter_id}&member_id={member_id}
GET /referrals?member_chapter_id={member_chapter_id}&member_id={member_id}&referral_direction=EXCHANGE
GET /referrals?member_chapter_id={member_chapter_id}&member_name=Rahul&date_from=2026-04-01&date_to=2026-04-30

App-admin listing filters:

Query param Required Notes
member_chapter_id Yes Selected app-admin member chapter. Can be sent as X-Member-Chapter-Id header instead.
member_id No Filters referrals where this member is either referring-by or referring-to.
referral_direction No Use uppercase values: EXCHANGE or SENT shows referrals given by the selected member_id. RECEIVED shows referrals received by the selected member_id. If member_id is not sent, this is relative to the logged-in app-admin member.
type No Backward-compatible alias for referral_direction. Prefer referral_direction in new app code.
search No Searches referring person, referral details, referring-by member name, referring-to member name, and exact created date.
q No Alias for search.
member_name No Filters by referring-by or referring-to member name.
from_date No Created date lower bound, for example 2026-04-01.
to_date No Created date upper bound, for example 2026-04-30.
date_from No Alias for from_date.
date_to No Alias for to_date.

App Admin: Create Referral

POST /referrals/store

Request:

{
  "member_chapter_id": "uuid",
  "member_id": "uuid",
  "referring_to_member_id": "uuid",
  "referring_person": "Ravi Shah",
  "referral_details": "Needs business automation consultation.",
  "contact_number": "9876543210",
  "email": "ravi@example.com"
}

referring_by_member_id is also accepted instead of member_id.

Validation:

Field Required Notes
member_chapter_id Yes Selected app-admin member chapter. Can be sent as X-Member-Chapter-Id header instead.
member_id Yes "Referring By" member selected by the app-admin screen.
referring_to_member_id Yes "Referring To" BCI member. Must be different from member_id.
referring_person Yes Person being referred.
referral_details Yes Specific requirement, opportunity, or service needed.
contact_number Yes Contact number for the referred person.
email Yes Email for the referred person.

Business Exchange APIs

These APIs back both business exchange screens from the app portal.

Every business exchange API must receive the selected member chapter. Send it as member_chapter_id in the query/body, or as the X-Member-Chapter-Id header.

The API decides the screen mode from the selected member chapter's member_type:

  • MEMBER: member mode.
  • Any other member type: app-admin mode.

Member: List Business Exchanges

GET /business-exchanges

Returns exchanges from the selected chapter where the logged-in member is either the referred-to member or the referred-by member.

Examples:

GET /business-exchanges?member_chapter_id={member_chapter_id}
GET /business-exchanges?member_chapter_id={member_chapter_id}&exchange_direction=EXCHANGE
GET /business-exchanges?member_chapter_id={member_chapter_id}&exchange_direction=RECEIVED
GET /business-exchanges?member_chapter_id={member_chapter_id}&search=Rahul&from_date=2026-04-01&to_date=2026-04-30

Member listing filters:

Query param Required Notes
member_chapter_id Yes Selected member chapter. Can be sent as X-Member-Chapter-Id header instead.
exchange_direction No Use uppercase values: EXCHANGE shows exchanges earned by the logged-in member. RECEIVED shows exchanges referred by the logged-in member.
search No Searches referral details, referred-to member name, referred-by member name, and exact created date.
q No Alias for search.
member_name No Filters by referred-to or referred-by member name.
from_date No Created date lower bound, for example 2026-04-01.
to_date No Created date upper bound, for example 2026-04-30.
date_from No Alias for from_date.
date_to No Alias for to_date.

List response:

{
  "message": "Business exchanges found.",
  "total_business_exchanges": 1,
  "total_business_amount_earned": "45000.00",
  "data": [
    {
      "id": "uuid",
      "chapter_id": "uuid",
      "referred_to_member_id": "uuid",
      "referred_by_member_id": "uuid",
      "business_amount_earned": "45000.00",
      "referral_details": "Website project closed from referral.",
      "referred_to_member": {
        "id": "member_uuid",
        "member_number": "BCI000002",
        "name": "Neha Patel",
        "email": "neha@example.com",
        "phone_number": "9876543211",
        "profile_image": "member-profiles/neha.jpg",
        "profile_image_url": "https://cdn.example.com/member-profiles/neha.jpg",
        "business_logo": "business-logos/neha-business/logo.png",
        "business_logo_url": "https://cdn.example.com/business-logos/neha-business/logo.png",
        "business": {
          "id": "business_uuid",
          "name": "Neha Fashion House",
          "business_logo": "business-logos/neha-business/logo.png",
          "business_logo_url": "https://cdn.example.com/business-logos/neha-business/logo.png"
        }
      },
      "referred_by_member": {
        "id": "member_uuid",
        "member_number": "BCI000001",
        "name": "Amit Shah",
        "email": "amit@example.com",
        "phone_number": "9876543210",
        "profile_image": "member-profiles/amit.jpg",
        "profile_image_url": "https://cdn.example.com/member-profiles/amit.jpg",
        "business_logo": "business-logos/amit-business/logo.png",
        "business_logo_url": "https://cdn.example.com/business-logos/amit-business/logo.png",
        "business": {
          "id": "business_uuid",
          "name": "Amit Electronics",
          "business_logo": "business-logos/amit-business/logo.png",
          "business_logo_url": "https://cdn.example.com/business-logos/amit-business/logo.png"
        }
      },
      "created_at": "2026-05-14T10:00:00.000000Z",
      "updated_at": "2026-05-14T10:00:00.000000Z"
    }
  ]
}

Notes:

  • profile_image and business_logo store the file path/key.
  • Use profile_image_url and business_logo_url for display.

Member: Create Business Exchange

POST /business-exchanges/store

Request:

{
  "member_chapter_id": "uuid",
  "referred_to_member_id": "uuid",
  "business_amount_earned": 45000,
  "referral_details": "Website project closed from referral."
}

Validation:

Field Required Notes
member_chapter_id Yes Selected member chapter. Can be sent as X-Member-Chapter-Id header instead.
referred_to_member_id Yes "Referred To" member selected from the member dropdown. Must belong to the selected chapter. Alias: referred_to.
business_amount_earned Yes Numeric amount, for example 45000.
referral_details Yes Referral or deal details.

Behavior:

  • For normal member flow, referred_by_member_id is automatically taken from the logged-in member.
  • Normal members must not send referred_by_member_id.
  • referred_to_member_id must be different from the logged-in member.
  • The created exchange stores the selected chapter as chapter_id.
  • Both members must belong to the selected chapter.

App Admin: Member Options

GET /business-exchanges/member-options

In app-admin mode, this returns members from the selected chapter so the "Referred To" and "Referred By" dropdowns can use the same options.

App Admin: List Business Exchanges

GET /business-exchanges

Examples:

GET /business-exchanges?member_chapter_id={member_chapter_id}&member_id={member_id}
GET /business-exchanges?member_chapter_id={member_chapter_id}&member_id={member_id}&exchange_direction=EXCHANGE
GET /business-exchanges?member_chapter_id={member_chapter_id}&member_name=Rahul&date_from=2026-04-01&date_to=2026-04-30

App-admin listing filters:

Query param Required Notes
member_chapter_id Yes Selected app-admin member chapter. Can be sent as X-Member-Chapter-Id header instead.
member_id No Filters exchanges where this member is either referred-to or referred-by.
exchange_direction No Use uppercase values: EXCHANGE shows exchanges earned by the selected member_id. RECEIVED shows exchanges referred by the selected member_id. If member_id is not sent, this is relative to the logged-in app-admin member.
search No Searches referral details, referred-to member name, referred-by member name, and exact created date.
q No Alias for search.
member_name No Filters by referred-to or referred-by member name.
from_date No Created date lower bound, for example 2026-04-01.
to_date No Created date upper bound, for example 2026-04-30.
date_from No Alias for from_date.
date_to No Alias for to_date.

App Admin: Create Business Exchange

POST /business-exchanges/store

Request:

{
  "member_chapter_id": "uuid",
  "referred_to_member_id": "uuid",
  "referred_by_member_id": "uuid",
  "business_amount_earned": 45000,
  "referral_details": "Website project closed from referral."
}

referred_to is also accepted instead of referred_to_member_id. referred_by is also accepted instead of referred_by_member_id.

Validation:

Field Required Notes
member_chapter_id Yes Selected app-admin member chapter. Can be sent as X-Member-Chapter-Id header instead.
referred_to_member_id Yes "Referred To" member selected by the app-admin screen.
referred_by_member_id Yes "Referred By" member selected by the app-admin screen. Must be different from referred_to_member_id.
business_amount_earned Yes Numeric amount, for example 45000.
referral_details Yes Referral or deal details.

Event APIs

These APIs back the member event listing, event detail, app-admin create event, attendance screens, and event photo gallery screens.

Every event API must receive the selected member chapter. Send it as member_chapter_id in the query/body, or as the X-Member-Chapter-Id header.

The API decides the screen mode from the selected member chapter's member_type:

  • MEMBER: member mode.
  • Any other member type: app-admin mode.

Visibility rules:

  • visibility_scope = CHAPTER: event is visible only to the selected chapter matching created_by_chapter_id.
  • visibility_scope = ALL: event is visible to all chapters and created_by_chapter_id is stored as null.
  • The app does not need to create multiple event-chapter rows for all-chapter events.

Image URL rules:

  • Event banner_image and event photo image_path store the S3 object key only.
  • Use banner_image_url and image_url in the API response for display. These URLs are built from the configured AWS CDN path.

List Events

GET /events

Returns upcoming and past events visible to the selected chapter.

Examples:

GET /events?member_chapter_id={member_chapter_id}
GET /events?member_chapter_id={member_chapter_id}&search=workshop
GET /events?member_chapter_id={member_chapter_id}&event_type_code=WORKSHOP_VISIT
GET /events?member_chapter_id={member_chapter_id}&from_date=2026-05-01&to_date=2026-05-31

Query params:

Query param Required Notes
member_chapter_id Yes Selected member chapter. Can be sent as X-Member-Chapter-Id header instead.
search No Searches title, description, location, event type name, and event type code.
q No Alias for search.
event_type_id No Filters by event type id.
event_type_code No Filters by event type code, for example EVENT, OFFICIAL_MEETING, WORKSHOP_VISIT.
status No One of ACTIVE, CANCELLED, POSTPONED, COMPLETED.
from_date No Event date lower bound.
to_date No Event date upper bound.
date_from No Alias for from_date.
date_to No Alias for to_date.

Success response:

{
  "message": "Events found.",
  "can_create_event": true,
  "total_upcoming_events": 1,
  "total_past_events": 1,
  "upcoming_events": [
    {
      "id": "uuid",
      "event_type_id": "uuid",
      "event_type": {
        "id": "uuid",
        "code": "WORKSHOP_VISIT",
        "name": "Workshop Visit"
      },
      "created_by_chapter_id": "uuid",
      "created_by_chapter": {
        "id": "uuid",
        "name": "Ahmedabad Chapter"
      },
      "title": "Strategic Management & Digital Transformation",
      "description": "Leadership and AI session.",
      "event_date": "2026-05-20",
      "start_time": "09:00",
      "end_time": "17:30",
      "location_name": "Innovation Hub Plaza",
      "location_address": "42 Business District",
      "latitude": "23.0225000",
      "longitude": "72.5714000",
      "map_url": "https://maps.example.com",
      "visibility_scope": "CHAPTER",
      "banner_image": "event-banners/banner.jpg",
      "banner_image_url": "https://cdn.example.com/event-banners/banner.jpg",
      "status": "ACTIVE",
      "is_attended": false,
      "attendance_id": null,
      "attendance_status": null,
      "total_attendees": 0,
      "total_photos": 0,
      "is_past": false
    }
  ],
  "past_events": []
}

App Admin: Create Event

POST /events/store
Content-Type: multipart/form-data

This API is available only in app-admin mode. A normal member receives 403 Forbidden.

Request example:

{
  "member_chapter_id": "uuid",
  "event_type_code": "WORKSHOP_VISIT",
  "title": "Strategic Management & Digital Transformation",
  "description": "Leadership and AI session.",
  "event_date": "2026-05-20",
  "start_time": "09:00",
  "end_time": "17:30",
  "location_name": "Innovation Hub Plaza",
  "location_address": "42 Business District",
  "latitude": 23.0225,
  "longitude": 72.5714,
  "map_url": "https://maps.example.com",
  "visibility_scope": "CHAPTER",
  "guests": [
    {
      "name": "Dr. Elena Vance",
      "company_name": "Strategic Futurist",
      "designation": "DC Dots"
    }
  ]
}

Validation:

Field Required Notes
member_chapter_id Yes Selected app-admin member chapter. Can be sent as X-Member-Chapter-Id header instead.
event_type_id Yes unless event_type_code is sent Must exist in event types.
event_type_code Yes unless event_type_id is sent One of EVENT, OFFICIAL_MEETING, WORKSHOP_VISIT.
title Yes Event name/title. Alias: event_name.
description No Event description.
event_date Yes Date string, for example 2026-05-20.
start_time Yes 24-hour time, for example 09:00.
end_time Yes 24-hour time after start_time, for example 17:30.
location_name No Venue/location name. Alias: location.
location_address No Full address. Alias: address.
latitude No Numeric latitude.
longitude No Numeric longitude.
map_url No External map URL.
visibility_scope Yes CHAPTER or ALL. Aliases: YOUR_CHAPTER, ALL_CHAPTERS through visible_to.
banner_image No JPG/JPEG/PNG/WEBP image, max 10 MB.
guests Yes Array, minimum one guest of honour.
guests.*.name Yes Guest name.
guests.*.company_name Yes Guest company name.
guests.*.designation Yes Guest designation.

Success response:

{
  "message": "Event created successfully.",
  "data": {
    "id": "uuid",
    "event_type": {
      "code": "WORKSHOP_VISIT",
      "name": "Workshop Visit"
    },
    "visibility_scope": "CHAPTER",
    "guests": [
      {
        "id": "uuid",
        "name": "Dr. Elena Vance",
        "company_name": "Strategic Futurist",
        "designation": "DC Dots",
        "sort_order": 1
      }
    ]
  }
}

Event Details

GET /events/details

Example:

GET /events/details?event_id={event_id}&member_chapter_id={member_chapter_id}

Query params:

Query param Required Notes
event_id Yes Event id.
member_chapter_id Yes Selected member chapter. Can be sent as X-Member-Chapter-Id header instead.

Success response:

{
  "message": "Event found.",
  "data": {
    "id": "uuid",
    "title": "Strategic Management & Digital Transformation",
    "guests": [],
    "photos": [],
    "is_attended": false,
    "total_attendees": 0,
    "total_photos": 0
  }
}

Member: Mark Own Attendance

POST /events/attendance/mark

This API is used when a member taps "Mark Attendance" on the event detail screen.

Request:

{
  "member_chapter_id": "uuid",
  "event_id": "uuid"
}

Notes:

  • The event must be visible to the selected chapter.
  • The event status must be ACTIVE.
  • Attendance can be marked only during the event window between event_date + start_time and event_date + end_time.
  • Before start time, the API returns Attendance cannot be marked before the event starts.
  • After end time, the API returns Attendance cannot be marked after the event ends.
  • The logged-in member is marked as PRESENT.
  • Calling it again updates the same attendance row.

Success response:

{
  "message": "Attendance marked successfully.",
  "data": {
    "id": "uuid",
    "event_id": "uuid",
    "member_id": "uuid",
    "status": "PRESENT",
    "marked_at": "2026-05-15T10:00:00.000000Z",
    "member": {}
  }
}

App Admin: Attendance Members

GET /events/attendance/members

This API is used for the app-admin attendance checkbox screen.

Examples:

GET /events/attendance/members?event_id={event_id}&member_chapter_id={member_chapter_id}
GET /events/attendance/members?event_id={event_id}&member_chapter_id={member_chapter_id}&tab=PRESENT
GET /events/attendance/members?event_id={event_id}&member_chapter_id={member_chapter_id}&search=David

Query params:

Query param Required Notes
event_id Yes Event id.
member_chapter_id Yes Selected app-admin member chapter. Can be sent as X-Member-Chapter-Id header instead.
tab No MEMBERS or PRESENT. Alias: type.
search No Searches member number, user name/email/phone, and business name/contact fields.
q No Alias for search.

Success response:

{
  "message": "Members found.",
  "total_members": 1,
  "data": [
    {
      "id": "uuid",
      "member_number": "BCI000001",
      "name": "David Henderson",
      "email": "david@example.com",
      "phone_number": "9876543210",
      "business": {
        "id": "uuid",
        "name": "Finance Hub"
      },
      "is_present": true,
      "attendance_status": "PRESENT"
    }
  ]
}

App Admin: Submit Attendance

POST /events/attendance/submit

This API is used when the app admin submits selected present members.

Request:

{
  "member_chapter_id": "uuid",
  "event_id": "uuid",
  "member_ids": [
    "member_uuid_1",
    "member_uuid_2"
  ]
}

Validation:

Field Required Notes
member_chapter_id Yes Selected app-admin member chapter. Can be sent as X-Member-Chapter-Id header instead.
event_id Yes Event id.
member_ids Yes Array, minimum one selected member. present_member_ids is also accepted.
member_ids.* Yes Must be an existing member and must belong to the selected chapter.

Notes:

  • The API only stores selected members as PRESENT.
  • It does not store ABSENT rows.
  • It does not remove previously marked present members. This supports submitting attendance in batches, for example 10 members at a time after searching.
  • Large submissions are saved using batch upsert.
  • For each newly marked present member, the backend creates an EVENT_ATTENDANCE notification with title Event Attendance and message Your attendance has been marked for {event_title}.
  • The attendance notification is not sent to the creator/action taker. Re-submitting a member who is already present does not create a duplicate attendance notification.
  • Attendance can be submitted only during the event window between event_date + start_time and event_date + end_time.
  • Before start time, the API returns Attendance cannot be marked before the event starts.
  • After end time, the API returns Attendance cannot be marked after the event ends.

Success response:

{
  "message": "Attendance submitted successfully.",
  "total_members": 500,
  "total_present_members": 18,
  "present_member_ids": [
    "member_uuid_1",
    "member_uuid_2"
  ]
}

Event Attendees

GET /events/attendance/attendees

This API returns members who are marked PRESENT for the event.

Example:

GET /events/attendance/attendees?event_id={event_id}&member_chapter_id={member_chapter_id}&search={search}

Query params:

Query param Required Notes
event_id Yes Event id.
member_chapter_id Yes Selected member chapter. Can be sent as X-Member-Chapter-Id header instead.
search No Searches attendee member number, name, email, phone number, business name, business email, or business mobile number.
q No Alias for search.

Success response:

{
  "message": "Attendees found.",
  "total_attendees": 1,
  "data": [
    {
      "id": "attendance_uuid",
      "event_id": "uuid",
      "member_id": "uuid",
      "status": "PRESENT",
      "marked_at": "2026-05-15T10:00:00.000000Z",
      "member": {
        "id": "uuid",
        "member_number": "BCI000001",
        "name": "David Henderson",
        "email": "david@example.com",
        "phone_number": "9876543210",
        "business": {
          "id": "uuid",
          "name": "Finance Hub"
        }
      }
    }
  ]
}

Event Photos

GET /events/photos

This API returns the event gallery photos for a visible event.

Example:

GET /events/photos?event_id={event_id}&member_chapter_id={member_chapter_id}

Query params:

Query param Required Notes
event_id Yes Event id.
member_chapter_id Yes Selected member chapter. Can be sent as X-Member-Chapter-Id header instead.

Success response:

{
  "message": "Event photos found.",
  "total_photos": 1,
  "data": [
    {
      "id": "photo_uuid",
      "event_id": "uuid",
      "image_path": "event-photos/{event_id}/photo.jpg",
      "image_url": "https://cdn.example.com/event-photos/{event_id}/photo.jpg",
      "caption": null,
      "sort_order": 1,
      "uploaded_by_member": {
        "id": "uuid",
        "member_number": "BCI000001",
        "name": "David Henderson",
        "email": "david@example.com",
        "phone_number": "9876543210",
        "business": {
          "id": "uuid",
          "name": "Finance Hub"
        }
      },
      "created_at": "2026-05-15T10:00:00.000000Z"
    }
  ]
}

When no records are found, message is Event photos not found., total_photos is 0, and data is an empty array.

Upload Event Photos

POST /events/photos/upload
Content-Type: multipart/form-data

This API is used from the attended event screen when a user uploads event gallery photos.

Upload permission:

  • App-admin members can upload photos for any visible event.
  • Normal members can upload photos only after they are marked PRESENT for that event.

Request fields:

Field Required Notes
member_chapter_id Yes Selected member chapter. Can be sent as X-Member-Chapter-Id header instead.
event_id Yes Event id.
photos[] Yes unless images[] is sent JPG/JPEG/PNG/WEBP images, max 10 MB each. Prefer this field in new app code.
images[] Yes unless photos[] is sent Backward-compatible alias for photos[].

Notes:

  • Files are uploaded to S3 under event-photos/{event_id}/....
  • The database stores only the S3 key in image_path.
  • Use image_url from the response for display; it is generated using the configured CDN path.
  • If upload fails, the API returns 422 with Event photos could not be uploaded. and does not create photo rows.

Success response:

{
  "message": "Event photos uploaded successfully.",
  "data": [
    {
      "id": "photo_uuid",
      "event_id": "uuid",
      "image_path": "event-photos/{event_id}/photo.jpg",
      "image_url": "https://cdn.example.com/event-photos/{event_id}/photo.jpg",
      "caption": null,
      "sort_order": 1,
      "uploaded_by_member": {
        "id": "uuid",
        "member_number": "BCI000001",
        "name": "David Henderson",
        "email": "david@example.com",
        "phone_number": "9876543210",
        "business": {
          "id": "uuid",
          "name": "Finance Hub"
        }
      },
      "created_at": "2026-05-15T10:00:00.000000Z"
    }
  ]
}

Common errors:

{
  "message": "Only attended members can upload event photos."
}
{
  "message": "Event photos could not be uploaded."
}

Delete Event Photo

DELETE /events/photos/{event_photo_id}

This API removes an uploaded photo from an event gallery.

Delete permission:

  • The member who uploaded the photo can delete it.
  • App-admin members can delete any photo belonging to a visible event.
  • Other members cannot delete the photo.

Request fields:

Field Required Notes
event_photo_id Yes Event photo UUID sent as the URL path parameter.
member_chapter_id Yes Selected member chapter. Send it in the request body or as the X-Member-Chapter-Id header.

Example:

DELETE /events/photos/{event_photo_id}
Content-Type: application/json
Authorization: Bearer {token}
{
  "member_chapter_id": "uuid"
}

The API deletes the image from S3 and soft-deletes its database record. The deleted photo will no longer be returned by GET /events/photos.

Success response:

{
  "message": "Event photo deleted successfully."
}

Common errors:

{
  "message": "You are not allowed to delete this event photo."
}
{
  "message": "Event photo was not found."
}
{
  "message": "Event photo could not be deleted."
}

OTP APIs

Signup: Send OTP

POST /auth/signup/send/otp

Request:

{
  "email": "member@example.com"
}

or:

{
  "phone_number": "9876543210"
}

Validation:

Field Required Notes
email_or_phone Conditional Required when email or phone_number is not sent. Must be a valid email or phone number.
email Conditional Alias for email_or_phone. Sends OTP using email template.
phone_number Conditional Alias for email_or_phone. Sends OTP using SMS service.

Success response:

{
  "message": "OTP sent successfully.",
  "expires_at": "2026-05-12T10:00:00.000000Z",
  "otp": "123456"
}

Notes:

  • OTP is valid for 5 minutes.
  • otp is returned only outside production. In production it will be null.
  • Test phone 5555555551 always receives OTP 123456.
  • Email signup OTP uses the emails.signup.otp template.
  • Phone signup OTP is sent through the SMS service.

Signup: Verify OTP

POST /auth/signup/verify/otp

Request:

{
  "email": "member@example.com",
  "otp": "123456"
}

or:

{
  "phone_number": "9876543210",
  "otp": "123456"
}

Validation:

Field Required Notes
email_or_phone Conditional Required when email or phone_number is not sent. Same email or phone where OTP was sent.
email Conditional Alias for email_or_phone.
phone_number Conditional Alias for email_or_phone.
otp Yes 6 digits, must exist, not expired, and not already used.

Success response:

{
  "message": "OTP verified successfully. Proceed to signup.",
  "next_step": "PROCEED_TO_SIGNUP"
}

Use next_step as the decision key:

next_step Meaning
PROCEED_TO_SIGNUP New account. Open the signup/member details form.
PROCEED_TO_BUSINESS_DETAILS Account exists but business details are missing. Open the business details form.
ACCOUNT_ALREADY_CREATED Stop signup. Show account already created error.

The signup API requires both email OTP and phone OTP to be verified before signup.

Signup Verify OTP With Account Status

Use this endpoint when the app already has both entered identifiers and needs account status checks.

POST /auth/signup/verify/otp

Request:

{
  "email_or_phone": "member@example.com",
  "otp": "123456"
}

Success response for a new account: 200 OK

{
  "message": "OTP verified successfully. Proceed to signup.",
  "next_step": "PROCEED_TO_SIGNUP"
}

Success response for an existing account without business details: 200 OK

{
  "token": "TEMP_BUSINESS_DETAILS_TOKEN",
  "is_business": false,
  "user": {
    "id": "uuid",
    "name": "Member Name",
    "email": "member@example.com",
    "phone_number": "9876543210",
    "approval_status": "PENDING",
    "is_approved": false
  },
  "message": "OTP verified successfully. Proceed to business details.",
  "next_step": "PROCEED_TO_BUSINESS_DETAILS"
}

Use token to open/save the business details screen. It has the business-details ability, same as the token returned from /auth/signup/verify.

Existing approved account or complete account response: 409 Conflict

{
  "message": "Account is already created.",
  "next_step": "ACCOUNT_ALREADY_CREATED"
}

If the email and phone are linked to different accounts, the API returns 422 Unprocessable Entity.

Auth APIs

Signup Member

POST /auth/signup/verify
Content-Type: multipart/form-data

Request fields:

Field Required Notes
name Yes Member name.
email Yes Must have verified registration OTP.
phone_number Yes Must have verified registration OTP.
password No Minimum 8 characters. If not provided, backend creates a random password.
date_of_birth No Date.
whatsapp No String, max 30.
profile_photo No JPG/JPEG/PNG image, max 2 MB.

Success response for new user: 201 Created

Success response for existing user with matching email and phone and no business details: 200 OK

{
  "token": "TEMP_BUSINESS_DETAILS_TOKEN",
  "is_business": false,
  "user": {
    "id": "uuid",
    "name": "Member Name",
    "email": "member@example.com",
    "phone_number": "9876543210",
    "approval_status": "PENDING",
    "is_approved": false
  }
}

Important:

  • This response returns token, not access_token.
  • This token has the business-details ability.
  • Use this token only for saving business details.
  • New signup accounts are created with approval_status: PENDING.
  • Unapproved members can complete business details with the temporary token, but they cannot log in to the app until admin approval.
  • If the user already has business details, registration returns 409 Conflict instead of another business-details token.
  • The account/business branching happens in /auth/signup/verify after both email and phone OTPs are verified.

Existing complete account response: 409 Conflict

{
  "message": "Account already exists."
}

Login

POST /auth/login

Request:

{
  "email_or_phone": "member@example.com",
  "password": "secret123",
  "device_name": "android",
  "app_type": "ANDROID",
  "app_version": "2.3.4"
}

Validation:

Field Required Notes
email_or_phone Yes Email or phone number.
password Yes Member password.
device_name No Used as token name. Defaults to app-login.
current_app_type No Use ANDROID or IOS. Aliases: app_type, platform. Lowercase values are accepted and normalized.
current_app_version No Current installed app version. Aliases: app_version, version.

Login success response:

{
  "token_type": "Bearer",
  "access_token": "APP_ACCESS_TOKEN",
  "requires_chapter_selection": false,
  "is_app_admin": false,
  "selected_chapter": {
    "member_chapter_id": "uuid",
    "chapter_id": "uuid",
    "date_of_joining": "2026-05-27",
    "name": "Chapter Name",
    "description": "Description"
  },
  "data": {
    "id": "member_uuid",
    "member_number": "BCI000001",
    "name": "Member Name",
    "email": "member@example.com",
    "phone_number": "9876543210",
    "profile_image": "member-profiles/photo.jpg",
    "profile_image_url": "https://cdn.example.com/member-profiles/photo.jpg",
    "member_type": "MEMBER",
    "member_type_id": "uuid",
    "approval_status": "APPROVED",
    "is_approved": true,
    "requires_password_change": true,
    "business": {
      "id": "business_uuid",
      "name": "Business Name",
      "business_logo": "business-logos/business_uuid/logo.png",
      "business_logo_url": "https://cdn.example.com/business-logos/business_uuid/logo.png"
    }
  }
}

Multiple chapter response:

{
  "token_type": "Bearer",
  "access_token": "SELECT_CHAPTER_TOKEN",
  "requires_chapter_selection": true,
  "chapters": [
    {
      "member_chapter_id": "uuid",
      "chapter_id": "uuid",
      "date_of_joining": "2026-05-27",
      "chapter": {
        "id": "uuid",
        "name": "Chapter Name",
        "description": "Description"
      },
      "member_type": {
        "id": "uuid",
        "code": "MEMBER",
        "name": "Member"
      },
      "is_app_admin": false
    }
  ]
}

Notes:

  • Only MEMBER users from the users table can log in through this app API.
  • Members with approval_status: PENDING receive 403 Forbidden with Your account is not approved yet.
  • Use requires_password_change: true to redirect the member to the create-password screen after admin approval.
  • If only one chapter is assigned to the member, login defaults to that chapter.
  • If more than one chapter is assigned, login returns a temporary select-chapter token and chapters.
  • If requires_password_change is true and only one chapter is assigned, login returns a temporary token with create-password ability instead of a normal app token.
  • data.member_type and data.member_type_id are taken from the selected chapter's member type.
  • is_app_admin is true when the selected chapter member type code is not MEMBER.
  • On successful login, the backend updates the member's current_app_type, current_app_version, last_login_at, and last_active_at. If app type/version are not sent, only login/activity timestamps are updated.
  • If no chapter is assigned, the API returns 403 with No chapter is assigned to this member.

Forgot Password: Send OTP

POST /auth/forgot-password/send-otp

Request:

{
  "email_or_phone": "member@example.com"
}

or:

{
  "email_or_phone": "9876543210"
}

Validation:

Field Required Notes
email_or_phone Yes Must be a valid email or phone number and must belong to an app member account.

Success response:

{
  "message": "OTP sent successfully.",
  "expires_at": "2026-05-12T10:00:00.000000Z",
  "otp": "123456"
}

Notes:

  • OTP is valid for 5 minutes.
  • otp is returned only outside production. In production it will be null.
  • Test phone 5555555551 always receives OTP 123456.
  • If no app member account exists, the API returns 422 Unprocessable Entity.

Forgot Password: Verify OTP

POST /auth/forgot-password/verify-otp

Request:

{
  "email_or_phone": "member@example.com",
  "otp": "123456"
}

Validation:

Field Required Notes
email_or_phone Yes Same email or phone where forgot-password OTP was sent.
otp Yes 6 digits, must exist, not expired, and not already used.

Success response:

{
  "message": "OTP verified successfully.",
  "token_type": "Bearer",
  "reset_token": "RESET_PASSWORD_TOKEN"
}

Token behavior:

  • The OTP is marked as used after successful verification.
  • reset_token has only the reset-password ability.
  • reset_token expires after 10 minutes.
  • Use this token only with /auth/forgot-password/reset.

Forgot Password: Reset Password

POST /auth/forgot-password/reset
Authorization: Bearer {reset_token}

Request:

{
  "password": "new-secret123",
  "password_confirmation": "new-secret123"
}

Validation:

Field Required Notes
password Yes Minimum 8 characters.
password_confirmation Yes Must match password.

Success response:

{
  "message": "Password reset successfully."
}

Token behavior:

  • The API requires a Sanctum bearer token with reset-password ability.
  • After success, all forgot-password-reset tokens for the user are deleted.
  • A normal app login token is not returned. The user should log in again.

Select Chapter

Use this only after login returns requires_chapter_selection: true.

POST /auth/select-chapter
Authorization: Bearer {select_chapter_token}

Request:

{
  "member_chapter_id": "uuid"
}

Success response:

{
  "token_type": "Bearer",
  "access_token": "APP_ACCESS_TOKEN",
  "requires_chapter_selection": false,
  "is_app_admin": false,
  "selected_chapter": {
    "member_chapter_id": "uuid",
    "chapter_id": "uuid",
    "date_of_joining": "2026-05-27",
    "name": "Chapter Name",
    "description": "Description"
  },
  "data": {
    "name": "Member Name",
    "email": "member@example.com",
    "phone_number": "9876543210",
    "member_type": "MEMBER",
    "member_type_id": "uuid"
  }
}

Token behavior:

  • The login response for multiple chapters returns a temporary token with select-chapter ability.
  • /auth/select-chapter deletes the temporary token.
  • If requires_password_change is false, /auth/select-chapter returns a normal app token.
  • If requires_password_change is true, /auth/select-chapter returns a temporary token with create-password ability.
  • The selected chapter is not stored by the backend.

Switch Chapter

Use this only after the member is already logged in with a normal app token. Do not use the temporary select-chapter token here.

POST /auth/switch-chapter
Authorization: Bearer {app_access_token}

Request:

{
  "member_chapter_id": "uuid"
}

Success response:

{
  "token_type": "Bearer",
  "access_token": "NEW_APP_ACCESS_TOKEN",
  "requires_chapter_selection": false,
  "is_app_admin": true,
  "selected_chapter": {
    "member_chapter_id": "uuid",
    "chapter_id": "uuid",
    "date_of_joining": "2026-05-27",
    "name": "Chapter Name",
    "description": "Description"
  },
  "data": {
    "name": "Member Name",
    "email": "member@example.com",
    "phone_number": "9876543210",
    "member_type": "CHAPTER_ADMIN",
    "member_type_id": "uuid"
  }
}

Token behavior:

  • /auth/switch-chapter requires a token with the app ability.
  • A temporary select-chapter token returns 403 with This token cannot switch chapter.
  • The selected member_chapter_id must belong to the logged-in member.
  • The current app token is deleted and a new app token is returned.
  • The app must replace its stored token with access_token from this response.

Logout

POST /auth/logout
Authorization: Bearer {app_access_token}

Success response:

{
  "message": "Logged out successfully."
}

Only the current token is deleted.

Profile APIs

Get Current Profile

GET /profile/me
Authorization: Bearer {app_access_token}

Use this after login/select-chapter/switch-chapter when the app needs the logged-in member's personal details, business details, and assigned chapters.

Success response:

{
  "message": "Profile found.",
  "data": {
    "id": "member_uuid",
    "name": "Member Name",
    "email": "member@example.com",
    "phone_number": "9876543210",
    "member_number": "BCI000001",
    "date_of_birth": "1992-01-15",
    "whatsapp": "9876543210",
    "profile_image": "member-profiles/photo.jpg",
    "profile_image_url": "https://cdn.example.com/member-profiles/photo.jpg",
    "current_app_type": "ANDROID",
    "current_app_version": "2.3.4",
    "last_login_at": "2026-05-18T10:30:00.000000Z",
    "last_active_at": "2026-05-18T10:30:00.000000Z",
    "business": {
      "id": "business_uuid",
      "name": "Business Name",
      "business_logo": "business-logos/business_uuid/logo.png",
      "business_logo_url": "https://cdn.example.com/business-logos/business_uuid/logo.png"
    },
    "member_chapters": [
      {
        "member_chapter_id": "uuid",
        "chapter_id": "uuid",
        "date_of_joining": "2026-05-27",
        "chapter": {
          "id": "uuid",
          "name": "Chapter Name",
          "description": "Description"
        },
        "member_type": {
          "id": "uuid",
          "code": "MEMBER",
          "name": "Member"
        }
      }
    ]
  }
}

If the authenticated user has no member profile, the API returns 404 with Member profile was not found.

Update Personal Details

POST /profile/update
Authorization: Bearer {app_access_token}
Content-Type: multipart/form-data

Use this for the edit personal details screen.

Request fields:

Field Required Notes
name Yes Full name. Alias: full_name.
date_of_birth No Date string, for example 1992-01-15.
whatsapp No Whatsapp number, max 30.
phone_number Yes Mobile number, max 30, unique in users. Alias: mobile_number.
email Yes Email, unique in users.
profile_photo No JPG/JPEG/PNG image, max 2 MB. Alias: profile_image.

Example:

{
  "full_name": "Rahul Sharma",
  "date_of_birth": "1992-01-15",
  "whatsapp": "912345678900",
  "mobile_number": "912345678901",
  "email": "rahul@example.com"
}

Success response:

{
  "message": "Profile updated successfully.",
  "data": {
    "id": "uuid",
    "name": "Rahul Sharma",
    "email": "rahul@example.com",
    "phone_number": "912345678901",
    "member_number": "BCI000001",
    "date_of_birth": "1992-01-15",
    "whatsapp": "912345678900",
    "profile_image": "member-profiles/photo.jpg",
    "profile_image_url": "https://cdn.example.com/member-profiles/photo.jpg",
    "current_app_type": "ANDROID",
    "current_app_version": "2.3.4",
    "last_login_at": "2026-05-18T10:30:00.000000Z",
    "last_active_at": "2026-05-18T10:30:00.000000Z",
    "business": {},
    "member_chapters": []
  }
}

Notes:

  • The API updates users.name, users.email, users.phone_number, and the logged-in member profile fields.
  • Profile photos are uploaded under member-profiles/...; use profile_image_url for display.
  • Business logos are uploaded under business-logos/...; use business.business_logo_url for display.
  • A token without the app ability returns 403 with This token cannot update profile.

Create Password

Use this for the first-login password setup screen when login or select-chapter returns requires_password_change: true.

POST /profile/create-password
Authorization: Bearer {create_password_token}

Request:

{
  "password": "new-password",
  "password_confirmation": "new-password"
}

Mobile field aliases are also accepted:

{
  "new_password": "new-password",
  "confirm_password": "new-password"
}

Validation:

Field Required Notes
password Yes New password, minimum 8 characters. Alias: new_password.
password_confirmation Yes Must match password. Alias: confirm_password.

Success response:

{
  "message": "Password created successfully.",
  "token_type": "Bearer",
  "access_token": "APP_ACCESS_TOKEN",
  "requires_chapter_selection": false,
  "is_app_admin": false,
  "selected_chapter": {
    "member_chapter_id": "uuid",
    "chapter_id": "uuid",
    "date_of_joining": "2026-05-27",
    "name": "Chapter Name",
    "description": "Description"
  },
  "data": {
    "id": "member_uuid",
    "member_number": "BCI000001",
    "name": "Member Name",
    "email": "member@example.com",
    "phone_number": "9876543210",
    "profile_image": "member-profiles/photo.jpg",
    "profile_image_url": "https://cdn.example.com/member-profiles/photo.jpg",
    "member_type": "MEMBER",
    "member_type_id": "uuid",
    "approval_status": "APPROVED",
    "is_approved": true,
    "requires_password_change": false
  }
}

Errors:

  • A token without the create-password ability returns 403 with This token cannot create password.
  • If password setup is no longer required for the account, the API returns 422 on password.

Token behavior:

  • This API requires the temporary create-password token.
  • The temporary token is deleted after success.
  • The API returns a fresh normal app token.
  • The app must replace its stored token with the returned access_token.

Change Password

POST /profile/change-password
Authorization: Bearer {app_access_token}

Request:

{
  "old_password": "old-password",
  "password": "new-password",
  "password_confirmation": "new-password"
}

Mobile field aliases are also accepted:

{
  "current_password": "old-password",
  "new_password": "new-password",
  "confirm_password": "new-password"
}

Validation:

Field Required Notes
old_password Yes Must match the logged-in user's current password. Alias: current_password.
password Yes New password, minimum 8 characters, must be different from old_password. Alias: new_password.
password_confirmation Yes Must match password. Alias: confirm_password.

Success response:

{
  "message": "Password changed successfully."
}

Errors:

  • A token without the app ability returns 403 with This token cannot change password.
  • Incorrect old password returns 422 on old_password.

App Settings APIs

These APIs back the App Settings notification toggles. They require the selected member chapter because they use the same app auth context as the rest of the app portal APIs.

Get Notification Settings

GET /settings/notifications
Authorization: Bearer {app_access_token}

Send the selected member chapter as member_chapter_id or X-Member-Chapter-Id.

Success response:

{
  "message": "Notification settings found.",
  "data": [
    {
      "key": "REFERRAL_RECEIVED",
      "type": "REFERRAL",
      "label": "Referral Received",
      "is_enabled": true
    },
    {
      "key": "ONE_TO_ONE_RECEIVED",
      "type": "SESSION",
      "label": "One to One Received",
      "is_enabled": true
    },
    {
      "key": "NEW_MEMBER_JOINED_CHAPTER",
      "type": "NEW_MEMBER_JOINED",
      "label": "New Member Joined Chapter",
      "is_enabled": true
    }
  ]
}

Notes:

  • The current backend returns only active notification types where can_disable = true.
  • As of now, that matches the three toggles in the app settings screen.

Update Notification Settings

POST /settings/notifications
Authorization: Bearer {app_access_token}

Send the selected member chapter as member_chapter_id or X-Member-Chapter-Id.

Request:

{
  "settings": [
    {
      "key": "REFERRAL_RECEIVED",
      "is_enabled": false
    },
    {
      "key": "ONE_TO_ONE_RECEIVED",
      "is_enabled": true
    }
  ]
}

Validation:

Field Required Notes
settings Yes Array, minimum 1 item.
settings.*.key Yes Must be an active notification type setting_key where can_disable = true.
settings.*.is_enabled Yes Boolean.

Success response:

{
  "message": "Notification settings updated successfully.",
  "data": [
    {
      "key": "REFERRAL_RECEIVED",
      "type": "REFERRAL",
      "label": "Referral Received",
      "is_enabled": false
    }
  ]
}

Notification APIs

These APIs back the app notification inbox and device token registration.

All notification APIs require:

  • Authorization: Bearer {app_access_token}
  • selected member chapter as member_chapter_id or X-Member-Chapter-Id

App Admin: Create General Notification

POST /notifications/store
Authorization: Bearer {app_access_token}
Content-Type: multipart/form-data

This API is available only in app-admin mode. A normal member receives 403 Forbidden.

Request fields:

Field Required Notes
member_chapter_id Yes Selected app-admin member chapter. Can be sent as X-Member-Chapter-Id header instead.
title Yes String, max 255.
message Yes Notification body.
audience Yes ALL_MEMBERS or CURRENT_CHAPTER_MEMBERS.
image No JPG/JPEG/PNG/WEBP image, max 10 MB.
notification_image No Alias for image.

Behavior:

  • CURRENT_CHAPTER_MEMBERS uses the currently selected chapter from member_chapter_id.
  • App does not send an arbitrary chapter_id for this API.
  • The creator App Admin is excluded from notification recipients and does not receive their own inbox or push notification.
  • Recipient generation runs through the queued notification flow.
  • If Firebase push is enabled and configured, backend also sends mobile push through Firebase FCM.
  • Firebase delivery is package-backed through kreait/laravel-firebase.

Request example:

{
  "member_chapter_id": "uuid",
  "title": "Monthly Meeting Reminder",
  "message": "Meeting starts at 6 PM.",
  "audience": "CURRENT_CHAPTER_MEMBERS"
}

Success response:

{
  "message": "General notification created successfully.",
  "data": {
    "id": "notification_uuid",
    "type": "GENERAL",
    "title": "Monthly Meeting Reminder",
    "message": "Meeting starts at 6 PM.",
    "image_path": null,
    "image_url": null,
    "audience": "CURRENT_CHAPTER_MEMBERS",
    "status": "PENDING",
    "sent_at": null,
    "created_at": "2026-06-02T10:30:00.000000Z"
  }
}

Save Device Token

POST /notifications/device-token
Authorization: Bearer {app_access_token}

Request:

{
  "device_token": "push-token",
  "platform": "ANDROID",
  "device_name": "Samsung A54",
  "app_version": "1.0.0"
}

Validation:

Field Required Notes
device_token Yes String, max 2048.
platform Yes ANDROID or IOS.
device_name No String, max 255.
app_version No String, max 50.

Success response:

{
  "message": "Device token saved successfully.",
  "data": {
    "id": "uuid",
    "device_token": "push-token",
    "platform": "ANDROID",
    "device_name": "Samsung A54",
    "app_version": "1.0.0",
    "last_used_at": "2026-06-02T10:30:00.000000Z"
  }
}

Notes:

  • Device token registration is required for real Firebase push delivery.
  • Inbox notifications still work even if the member has no active device token.

List Notifications

GET /notifications
Authorization: Bearer {app_access_token}

Examples:

GET /notifications?member_chapter_id={member_chapter_id}
GET /notifications?member_chapter_id={member_chapter_id}&is_read=0
GET /notifications?member_chapter_id={member_chapter_id}&type=REFERRAL
GET /notifications?member_chapter_id={member_chapter_id}&page=1&limit=10

Query params:

Query param Required Notes
member_chapter_id Yes Selected member chapter. Can be sent as X-Member-Chapter-Id header instead.
type No One of the notification type codes such as REFERRAL, SESSION, EVENT, EVENT_ATTENDANCE, SUBSCRIPTION, GENERAL, CHAPTER_ASSIGNED.
is_read No Boolean filter. 1 for read, 0 for unread.
limit No Pagination size.
page No Page number.

Success response:

{
  "message": "Notifications found.",
  "meta": {
    "total_records": 1,
    "page": 1,
    "limit": 10,
    "total_pages": 1,
    "record_start": 1,
    "record_end": 1
  },
  "data": [
    {
      "id": "recipient_uuid",
      "notification_id": "notification_uuid",
      "type": "REFERRAL",
      "title": "New Referral",
      "message": "Amit Shah sent a referral to Neha Patel.",
      "image_path": null,
      "image_url": null,
      "metadata": {
        "source_id": "referral_uuid"
      },
      "delivery_status": "SENT",
      "is_read": false,
      "read_at": null,
      "delivered_at": "2026-06-02T10:30:00.000000Z",
      "created_at": "2026-06-02T10:30:00.000000Z"
    }
  ]
}

Mark Notification As Read

POST /notifications/{notificationRecipient}/read
Authorization: Bearer {app_access_token}

Success response:

{
  "message": "Notification marked as read.",
  "data": {
    "id": "recipient_uuid",
    "notification_id": "notification_uuid",
    "type": "REFERRAL",
    "title": "New Referral",
    "message": "Amit Shah sent a referral to Neha Patel.",
    "delivery_status": "READ",
    "is_read": true,
    "read_at": "2026-06-02T10:35:00.000000Z"
  }
}

If the notification does not belong to the logged-in member, the API returns 404 with Notification was not found.

Mark All Notifications As Read

POST /notifications/read-all
Authorization: Bearer {app_access_token}

Success response:

{
  "message": "All notifications marked as read."
}

Master APIs

Most master APIs are public. Endpoints that show an Authorization header require an app token.

Business Categories

GET /masters/business/categories

Success response:

{
  "message": "Business categories found.",
  "data": [
    {
      "id": "uuid",
      "name": "Category Name",
      "description": "Description"
    }
  ]
}

Business Sub Categories

GET /masters/business/sub-categories?business_category_id={category_id}

Query params:

Field Required Notes
business_category_id Yes for useful data Parent category id.

Success response:

{
  "message": "Business sub categories found.",
  "data": [
    {
      "id": "uuid",
      "parent_id": "uuid",
      "name": "Sub Category Name",
      "description": "Description"
    }
  ]
}

Countries

GET /masters/countries

Success response:

{
  "message": "Countries found.",
  "data": [
    {
      "id": "uuid",
      "name": "India",
      "iso2": "IN",
      "iso3": "IND",
      "phone_code": "91"
    }
  ]
}

States

GET /masters/states?country_id={country_id}

Query params:

Field Required Notes
country_id Yes for useful data Country id.

Success response:

{
  "message": "States found.",
  "data": [
    {
      "id": "uuid",
      "country_id": "uuid",
      "name": "Gujarat",
      "code": "GJ"
    }
  ]
}

Cities

GET /masters/cities?state_id={state_id}

Query params:

Field Required Notes
state_id Yes for useful data State id.

Success response:

{
  "message": "Cities found.",
  "data": [
    {
      "id": "uuid",
      "state_id": "uuid",
      "name": "Ahmedabad",
      "latitude": "23.0225",
      "longitude": "72.5714"
    }
  ]
}

AWS Details

GET /masters/aws-details
Authorization: Bearer {app_access_token}

Success response:

{
  "message": "AWS details found.",
  "data": {
    "id": 1,
    "bucket_name": "bucket-name",
    "cdn_path": "https://cdn.example.com"
  }
}

Secret fields such as secret_access_key, payment working keys, and access codes are not returned.

App Versions

GET /masters/app-versions?platform=ANDROID

Use this when the mobile app needs the currently configured app version before or after login. No bearer token is required, but if an app token is sent the backend updates that member's app tracking details.

Examples:

GET /masters/app-versions?platform=ANDROID
GET /masters/app-versions?app_type=ios&app_version=2.0.1

Query params:

Field Required Notes
platform Yes Use ANDROID or IOS. Lowercase values are accepted and normalized.
app_type Yes if platform is not sent Alias for platform.
current_app_version No Current installed app version to store against the member when a bearer token is sent. Aliases: app_version, version.

Success response:

{
  "message": "App version found.",
  "data": {
    "id": "uuid",
    "platform": "ANDROID",
    "version": "2.3.4",
    "force_update": "YES",
    "is_force_update": true,
    "url": "https://play.google.com/store/apps/details?id=com.bci.app",
    "description": "Release notes"
  }
}

When no active record is found for the requested platform, message is App version not found. and data is null.

Tracking behavior:

  • Without a bearer token, this API only returns the configured app version.
  • With a valid app bearer token, this API updates the logged-in member's current_app_type, optional current_app_version, and last_active_at.
  • This API does not update last_login_at; that remains tied to /auth/login.

Contact Us Details

GET /masters/contact-us-details

Use this for the Contact Us screen. No bearer token is required.

Success response:

{
  "message": "Contact us details found.",
  "data": {
    "id": "uuid",
    "phone_number": "+1(555) 012-3456",
    "email_address": "jsjenkins@cloudscale.com"
  }
}

When no active record is found, message is Contact us details not found. and data is null.

Dynamic URLs

GET /masters/dynamic-urls

Use this for static web links that should be controlled from the backend. No bearer token is required.

Success response:

{
  "message": "Dynamic URLs found.",
  "data": {
    "id": "uuid",
    "privacy_policy_url": "https://example.com/privacy",
    "delete_account_url": "https://example.com/delete-account",
    "about_us_url": "https://example.com/about-us",
    "terms_and_condition_url": "https://example.com/terms"
  }
}

When no active record is found, message is Dynamic URLs not found. and data is null.

Complaint Types

GET /masters/complaint-types

Use this for the Grievance screen complaint type chips/dropdown. No bearer token is required.

Success response:

{
  "message": "Complaint types found.",
  "data": [
    {
      "id": "uuid",
      "code": "ADMIN",
      "name": "Admin",
      "description": null
    }
  ]
}

When no active records are found, message is Complaint types not found. and data is an empty array.

Chapters

GET /masters/chapters

Optional filtered request:

GET /masters/chapters?country_id={country_id}&state_id={state_id}&city_id={city_id}&business_category_id={category_id}&business_sub_category_id={sub_category_id}

Query params:

Field Required Notes
country_id No Filters chapter assignment by country.
state_id No Filters chapter assignment by state.
city_id No Filters chapter assignment by city.
business_category_id No Filters chapter assignment by business category.
business_sub_category_id No Filters chapter assignment by business sub category.

Notes:

  • If any query params are passed, the API uses only request filters.
  • If no query params are passed and a bearer token is sent, the API filters by the logged-in user's member.business location and category fields.
  • If no query params and no logged-in business are available, the API returns all active chapters.

Success response:

{
  "message": "Chapters found.",
  "data": [
    {
      "id": "uuid",
      "name": "Chapter Name",
      "description": "Description"
    }
  ]
}

Event Types

GET /masters/event-types
Authorization: Bearer {app_access_token}

Use this for the create-event type dropdown.

Success response:

{
  "message": "Event types found.",
  "data": [
    {
      "id": "uuid",
      "code": "EVENT",
      "name": "Event"
    },
    {
      "id": "uuid",
      "code": "OFFICIAL_MEETING",
      "name": "Official Meeting"
    },
    {
      "id": "uuid",
      "code": "WORKSHOP_VISIT",
      "name": "Workshop Visit"
    }
  ]
}

Code Of Conduct PDF

GET /masters/code-of-conduct-pdf
Authorization: Bearer {app_access_token}

Success response:

{
  "message": "Code of conduct PDF found.",
  "data": {
    "id": "uuid",
    "title": "Code of Conduct",
    "pdf_path": "code-of-conduct.pdf",
    "url": "https://example.com/code-of-conduct.pdf",
    "pdf_url": "https://example.com/code-of-conduct.pdf",
    "description": "Description"
  }
}

Member Chapter API

Submit Member Chapter

Use this after the member has selected a chapter from /masters/chapters.

POST /member-chapters/submit
Authorization: Bearer {app_access_token}

Request:

{
  "chapter_id": "uuid",
  "date_of_joining": "2026-05-27"
}

Validation:

Field Required Notes
chapter_id Yes Must be an active chapter id.
date_of_joining No Joining date for the selected chapter. Format: YYYY-MM-DD.

Success response:

{
  "message": "Chapter request submitted successfully.",
  "data": {
    "id": "uuid",
    "member_id": "uuid",
    "chapter_id": "uuid",
    "member_type_id": "uuid",
    "date_of_joining": "2026-05-27",
    "chapter": {
      "id": "uuid",
      "name": "Chapter Name",
      "description": "Description"
    },
    "member_type": {
      "id": "uuid",
      "code": "MEMBER",
      "name": "Member"
    }
  }
}

Notes:

  • The API uses the authenticated user's member profile.
  • The backend assigns member type MEMBER.
  • Submitting again updates the selected chapter for the same member/member type.

Business Details API

Save Business Details

POST /business/store
Authorization: Bearer {business_details_token_or_app_access_token}
Content-Type: multipart/form-data

Request:

{
  "business_category_id": "uuid",
  "business_sub_category_id": "uuid",
  "country_id": "uuid",
  "state_id": "uuid",
  "city_id": "uuid",
  "name": "Business Name",
  "gst_number": "24ABCDE1234F1Z5",
  "mobile_number": "9876543210",
  "whatsapp_number": "9876543210",
  "email": "business@example.com",
  "website": "https://example.com",
  "description": "Business description",
  "full_address": "Full business address",
  "business_logo": "business-logos/business_uuid/logo.png",
  "delete_business_image_ids": ["uuid"]
}

For business photos, send multipart/form-data:

  • business_logo: JPG/JPEG/PNG/WEBP image, max 2 MB.
  • Alias: logo or business_logo_image.
  • business_images[]: JPG/JPEG/PNG/WEBP images, max 10 MB each.
  • Alias: photos[].
  • Max total images per business: 6.
  • delete_business_image_ids[]: existing business image ids to remove when updating an existing business.
  • Alias: deleted_image_ids[].

Validation:

Field Required Notes
business_category_id Yes Must exist in business categories.
business_sub_category_id Yes Must exist in business categories.
country_id Yes Must exist in countries.
state_id Yes Must exist in states.
city_id Yes Must exist in cities.
name Yes String, max 255.
gst_number No String, max 255.
mobile_number No String, max 30. Defaults from member phone number when empty.
whatsapp_number No String, max 30. Defaults from member whatsapp/phone number when empty.
email No Valid email, max 255. Defaults from member email when empty.
website No Valid URL, max 255.
description No String.
full_address No String.
business_logo No JPG/JPEG/PNG/WEBP image, max 2 MB. Alias: logo or business_logo_image.
business_images[] No JPG/JPEG/PNG/WEBP images, max 10 MB each. Alias: photos[].
delete_business_image_ids[] No Existing business image ids to delete. Alias: deleted_image_ids[].

Success response:

{
  "message": "Business details saved successfully.",
  "token_type": "Bearer",
  "access_token": "APP_ACCESS_TOKEN",
  "is_business": true,
  "data": {
    "id": "business_uuid",
    "name": "Business Name",
    "business_logo": "business-logos/business_uuid/logo.png",
    "business_logo_url": "https://cdn.example.com/business-logos/business_uuid/logo.png",
    "images": [
      {
        "id": "uuid",
        "business_id": "business_uuid",
        "image_path": "business-images/business_uuid/photo.jpg",
        "image_url": "https://cdn.example.com/business-images/business_uuid/photo.jpg",
        "caption": null,
        "sort_order": 1,
        "created_at": "2026-05-23T09:30:00.000000Z"
      }
    ]
  }
}

Token behavior:

  • A business-details token can save business details once and is deleted after success.
  • The API returns a new app token after saving business details.
  • An existing app token can also update business details.
  • Business details are created or updated against the logged-in member.
  • business_logo stores the uploaded path/key; use business_logo_url for display.

Error Handling

Common error responses:

Validation Error

HTTP status: 422

{
  "message": "The email field is required.",
  "errors": {
    "email": [
      "The email field is required."
    ]
  }
}

Unauthenticated

HTTP status: 401

{
  "message": "Unauthenticated."
}

Token Cannot Save Business Details

HTTP status: 403

{
  "message": "This token cannot update business details."
}

Token Cannot Create Password

HTTP status: 403

{
  "message": "This token cannot create password."
}

Member Profile Missing

HTTP status: 404

{
  "message": "Member profile was not found."
}

Recommended App State Flow

After registration:

  • If is_business is false, navigate user to business details form.
  • Save the returned token as temporary token for /business/store.
  • After business details are saved, replace temporary token with returned access_token.

After login:

  • Save access_token.
  • Register the current device push token using /notifications/device-token.
  • If requires_chapter_selection is true, call /auth/select-chapter with the temporary token and replace it with the returned access_token.
  • If the returned payload has requires_password_change: true, open the create-password screen and call /profile/create-password with the temporary create-password token.
  • After /profile/create-password succeeds, replace the stored token with the returned normal access_token.
  • To change chapters later, call /auth/switch-chapter with the current app token and replace it with the returned access_token.
  • Load app settings toggles from /settings/notifications after chapter selection is available.
  • Load inbox data from /notifications and mark read state using /notifications/{notificationRecipient}/read or /notifications/read-all.
  • Use /auth/me to refresh current profile if needed.
  • If business details are not present in the loaded member data, ask user to complete business details.