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
- Fetch app versions and enforce update behavior if needed.
- Send signup OTP to email using
/auth/signup/send/otp. - Verify email OTP using
/auth/signup/verify/otp. - Send signup OTP to phone number using
/auth/signup/send/otp. - Verify phone OTP using
/auth/signup/verify/otp. - Complete signup using
/auth/signup/verify. - Fetch master data for business form.
- Save business details using the temporary
business-detailstoken. - Store the returned
apptoken for normal app usage. - Register the active device token using
/notifications/device-token. - Fetch available chapters.
- Submit the selected member chapter.
- Use notification settings APIs for app settings toggles.
- Use notification inbox APIs for notification listing and read state.
- Use member listing API for the members tab.
- If selected member type is app-admin, use add-member API from the members tab.
- Use member details API when opening a member profile from the members tab.
- If selected member type is app-admin, use member profile update API to edit another member's profile.
- If selected member type is app-admin, use member business update API to edit another member's business details.
- Use business listing and business details APIs for the business directory.
- Use profile APIs for current profile, edit personal details, and change password.
- Use 1:1 session APIs for member meeting entries.
- Use referral APIs for referral entries.
- Use event APIs for event listing, event detail, attendance marking, app-admin attendance submission, and event photo gallery/upload.
- Use contact-us details API for the Contact Us screen.
- Use grievance APIs for the Grievance screen.
- 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_birthmonth 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_dategreater than or equal to the current server date. - Excludes
CANCELLEDandCOMPLETEDevents. - 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_sessionspoints_earnedreferral_takenreferral_givenevent_attendedattendancetotal_business_exchange
- App-admin response keys:
total_memberstotal_referralstotal_business_exchangeearningspoints_earnedeventsattendance
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_joiningis 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,
attendanceis0.00%. - For normal members, counts are selected-chapter scoped.
- For app-admin:
total_business_exchangeis overall across all chapters.earningsis only for the selected chapter.points_earnedis 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_idis resolved automatically fromearned_at.- Current financial year is April 1 to March 31.
expired_atis calculated from the currentpoint_rulesrow 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
limitis accepted from 1 to 50. - Sorted by latest activity first.
- For the home preview, call without
pageand withoutview. - For View All listing, send
view=LIST&page=1&limit=10. This returnsmetaand 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
- Send forgot-password OTP to the member email or phone number.
- Verify the OTP.
- Store the returned temporary
reset_token. - Create the new password using the
reset_token. - 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: trueonly in app-admin mode. - Send
chapter_idonly 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:
usersrow withtype = MEMBER.membersprofile row.member_businessesrow.member_chaptersrow with member typeMEMBER.NEW_MEMBER_JOINEDnotification 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_idto 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:
logoorbusiness_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_imageandbusiness_logostore the file path/key.- Use
profile_image_urlandbusiness_logo_urlfor 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_idis automatically taken from the logged-in member. - Normal members must not send
referred_by_member_id. referred_to_member_idmust 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 matchingcreated_by_chapter_id.visibility_scope = ALL: event is visible to all chapters andcreated_by_chapter_idis stored asnull.- The app does not need to create multiple event-chapter rows for all-chapter events.
Image URL rules:
- Event
banner_imageand event photoimage_pathstore the S3 object key only. - Use
banner_image_urlandimage_urlin 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_timeandevent_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
ABSENTrows. - 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_ATTENDANCEnotification with titleEvent Attendanceand messageYour 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_timeandevent_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
PRESENTfor 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_urlfrom the response for display; it is generated using the configured CDN path. - If upload fails, the API returns
422withEvent 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.
otpis returned only outside production. In production it will benull.- Test phone
5555555551always receives OTP123456. - Email signup OTP uses the
emails.signup.otptemplate. - 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, notaccess_token. - This token has the
business-detailsability. - 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 Conflictinstead of another business-details token. - The account/business branching happens in
/auth/signup/verifyafter 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
MEMBERusers from theuserstable can log in through this app API. - Members with
approval_status: PENDINGreceive403 ForbiddenwithYour account is not approved yet. - Use
requires_password_change: trueto 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-chaptertoken andchapters. - If
requires_password_changeistrueand only one chapter is assigned, login returns a temporary token withcreate-passwordability instead of a normalapptoken. data.member_typeanddata.member_type_idare taken from the selected chapter's member type.is_app_administruewhen the selected chapter member type code is notMEMBER.- On successful login, the backend updates the member's
current_app_type,current_app_version,last_login_at, andlast_active_at. If app type/version are not sent, only login/activity timestamps are updated. - If no chapter is assigned, the API returns
403withNo 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.
otpis returned only outside production. In production it will benull.- Test phone
5555555551always receives OTP123456. - 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_tokenhas only thereset-passwordability.reset_tokenexpires 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-passwordability. - After success, all
forgot-password-resettokens for the user are deleted. - A normal
applogin 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-chapterability. /auth/select-chapterdeletes the temporary token.- If
requires_password_changeisfalse,/auth/select-chapterreturns a normalapptoken. - If
requires_password_changeistrue,/auth/select-chapterreturns a temporary token withcreate-passwordability. - 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-chapterrequires a token with theappability.- A temporary
select-chaptertoken returns403withThis token cannot switch chapter. - The selected
member_chapter_idmust 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_tokenfrom 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/...; useprofile_image_urlfor display. - Business logos are uploaded under
business-logos/...; usebusiness.business_logo_urlfor display. - A token without the
appability returns403withThis 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-passwordability returns403withThis token cannot create password. - If password setup is no longer required for the account, the API returns
422onpassword.
Token behavior:
- This API requires the temporary
create-passwordtoken. - The temporary token is deleted after success.
- The API returns a fresh normal
apptoken. - 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
appability returns403withThis token cannot change password. - Incorrect old password returns
422onold_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_idorX-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_MEMBERSuses the currently selected chapter frommember_chapter_id.- App does not send an arbitrary
chapter_idfor 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, optionalcurrent_app_version, andlast_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.businesslocation 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:
logoorbusiness_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-detailstoken can save business details once and is deleted after success. - The API returns a new
apptoken after saving business details. - An existing
apptoken can also update business details. - Business details are created or updated against the logged-in member.
business_logostores the uploaded path/key; usebusiness_logo_urlfor 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_businessisfalse, navigate user to business details form. - Save the returned
tokenas 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_selectionistrue, call/auth/select-chapterwith the temporary token and replace it with the returnedaccess_token. - If the returned payload has
requires_password_change: true, open the create-password screen and call/profile/create-passwordwith the temporarycreate-passwordtoken. - After
/profile/create-passwordsucceeds, replace the stored token with the returned normalaccess_token. - To change chapters later, call
/auth/switch-chapterwith the current app token and replace it with the returnedaccess_token. - Load app settings toggles from
/settings/notificationsafter chapter selection is available. - Load inbox data from
/notificationsand mark read state using/notifications/{notificationRecipient}/reador/notifications/read-all. - Use
/auth/meto refresh current profile if needed. - If business details are not present in the loaded member data, ask user to complete business details.