BettahLife API Documentation
REST API Reference — v1.0
Base URL
https://your-domain.com/api
All endpoints listed below are relative to this base URL.
Authentication
The API uses Laravel Sanctum token authentication. After logging in or registering, include the token in subsequent requests:
Authorization: Bearer {api_token}
Endpoints marked Auth Required need this header. Endpoints marked Public do not.
Error Handling
Standard HTTP status codes are used. Validation errors return 422 with a JSON body:
{
"message": "The given data was invalid.",
"errors": {
"field": ["Error message"]
}
}
| Code | Meaning |
|---|---|
200 | Success |
201 | Created |
204 | No Content (successful delete) |
401 | Unauthenticated |
403 | Forbidden |
404 | Not Found |
410 | Gone (expired resource) |
422 | Validation Error |
500 | Server Error |
Auth
POST /login Public
Authenticate a user and receive an API token.
| Parameter | Type | Rules |
|---|---|---|
username | string | required — email or phone number |
password | string | required |
// Response 200
{
"data": {
"id": 1,
"firstname": "John",
"lastname": "Doe",
"email": "john@example.com",
"api_token": "1|abc123...",
...
}
}
POST /register Public
Create a new user account. Awards 5 BettahPoints on registration.
| Parameter | Type | Rules |
|---|---|---|
firstname | string | required |
lastname | string | required |
email | string | required — unique |
password | string | required — confirmed, min:8 |
password_confirmation | string | required |
date_of_birth | date | required |
gender | string | required — male|female |
country_code | string | required |
nickname | string | optional |
occupation | string | optional |
GET /user Auth Required
Get the currently authenticated user with phones, addresses, and coach info.
POST /logout Auth Required
Revoke the current API token.
Password Reset
POST /password_reset/request_code Public
Send a 6-digit OTP to the user's phone via Twilio.
| Parameter | Type | Rules |
|---|---|---|
username | string | required — email or phone |
POST /password_reset/verify_code Public
Verify the OTP code.
| Parameter | Type | Rules |
|---|---|---|
username | string | required |
code | integer | required — 6 digits |
POST /password_reset/new_password Public
Set a new password after OTP verification.
| Parameter | Type | Rules |
|---|---|---|
username | string | required |
password | string | required — confirmed |
password_confirmation | string | required |
Users
GET /users
Paginated list of users (50 per page).
POST /users
Create a user (admin use).
| Parameter | Type | Rules |
|---|---|---|
email | string | required — unique |
firstname | string | required |
lastname | string | required |
gender | string | required — male|female |
country_code | string | required |
date_of_birth | date | required |
password | string | required — confirmed |
nickname | string | optional |
occupation | string | optional |
national_id | string | optional — unique |
GET /users/{user}
Get a single user with phones, addresses, coach info, and BettahPoints balance.
PUT /users/{user}
Update a user. Awards 2 BettahPoints on first profile completion (firstname, lastname, date_of_birth, gender, country_code all filled).
DELETE /users/{user}
Soft-delete a user. Cannot delete your own account. Returns 204.
User Photo
POST /users/{user}/photo
Upload a profile photo (jpg, jpeg, png).
DELETE /users/{user}/photo
Remove the profile photo.
Notification Preferences
PUT /users/{user}/notification_preferences
Update notification settings.
| Parameter | Type | Rules |
|---|---|---|
event_reminders | boolean | optional |
sms_notifications | boolean | optional |
push_notifications | boolean | optional |
email_notifications | boolean | optional |
newsletter_subscription | boolean | optional |
marketing_sms_notifications | boolean | optional |
marketing_email_notifications | boolean | optional |
Medical Info
PUT /users/{user}/medical_info
Update medical information.
| Parameter | Type | Rules |
|---|---|---|
height | numeric | optional |
weight | numeric | optional |
allergies | string | optional |
blood_type | string | optional |
medication | string | optional |
known_ailments | string | optional |
favorite_sport | string | optional |
User Phones
GET /users/{user}/phones
Paginated list (50/page).
POST /users/{user}/phones
| Parameter | Type | Rules |
|---|---|---|
type | string | required |
number | string | required — unique |
label | string | optional |
is_default | boolean | optional |
country_code | string | optional |
has_whatsapp | boolean | optional |
GET /users/{user}/phones/{phone}
Show a single phone record.
PUT /users/{user}/phones/{phone}
Update a phone record.
DELETE /users/{user}/phones/{phone}
Delete a phone record. Returns 204.
User Addresses
GET /users/{user}/addresses
Paginated list. Filter with ?type=home|work|other.
POST /users/{user}/addresses
| Parameter | Type | Rules |
|---|---|---|
type | string | required — home|work|other |
street1 | string | required |
city | string | required |
state | string | required |
postal_code | string | required |
country_code | string | required |
street2 | string | optional |
label | string | optional |
is_default | boolean | optional |
GET /users/{user}/addresses/{address}
Show a single address.
PUT /users/{user}/addresses/{address}
Update an address.
DELETE /users/{user}/addresses/{address}
Delete an address. Returns 204.
Coaches
individual (sole coach) and organization (company/group). BettahLife itself is an organization identified by is_platform = true.GET /coaches
Paginated list (15/page) with admins, users, owner, and documents.
POST /coaches
| Parameter | Type | Rules |
|---|---|---|
user_id | integer | required |
name | string | required |
email | string | required — unique |
description | string | required |
address | string | required |
phone | string | required — unique |
tags | string | optional |
secondary_phone | string | optional |
x, tiktok, website, youtube, facebook, linkedin, instagram | string | optional — social links |
GET /coaches/{coach}
Full coach details with admins, users, documents, follower/subscriber counts.
PUT /coaches/{coach}
Update coach details.
POST /coaches/{coach}/in_progress
Set coach status to pending (in progress).
Coach Logo & Cover Photo
POST /coaches/{coach}/logo?type={logo|cover_photos}
Upload logo or cover photo. Send as file upload.
DELETE /coaches/{coach}/logo?type={logo|cover_photos}
Remove logo or cover photo. Returns 204.
Coach Documents
POST /coaches/{coach}/documents?type={document_type}
Upload a document. Replaces existing document of the same type.
DELETE /coaches/{coach}/documents/{document}
Delete a document.
Coach Invitations
GET /coaches/{coach}/invitations
List all invitations for a coach.
POST /coaches/{coach}/invitations
Send an invitation.
| Parameter | Type | Rules |
|---|---|---|
email | string | required without phone |
phone | string | required without email |
role | string | required — admin|subscriber |
// Response 200
{
"id": 1,
"role": "subscriber",
"email": "user@example.com",
"phone": null,
"token": "uuid-token",
"expires_at": "2026-03-26T00:00:00Z"
}
GET /coaches/{coach}/invitations/{token}
View invitation details by token.
POST /coaches/{coach}/invitations/{token}/accept
Accept an invitation. Admin invites set user.coach_id; subscriber invites add a subscriber relation. Returns 410 if expired.
DELETE /coaches/{coach}/invitations/{token}
Decline an invitation. Returns 204.
Follow / Unfollow
POST /users/{user}/coaches/{coach}/follow
Follow a coach.
POST /users/{user}/coaches/{coach}/unfollow
Unfollow a coach.
Events
GET /events
Paginated list (15/page) with extensive filtering.
| Query Param | Description |
|---|---|
subscribed | Filter to user's subscribed events only |
period | upcoming, ongoing, or past |
coach_id | Filter by coach |
event_type_id | Filter by event type |
event_category_id | Filter by category |
event_frequency_id | Filter by frequency |
location | Wildcard search on address |
searchword | Wildcard search on title, description, tags |
start_date / end_date | Date range filter |
POST /events
| Parameter | Type | Rules |
|---|---|---|
coach_id | integer | required |
created_by | integer | required |
event_type_id | integer | required |
event_category_id | integer | required |
event_frequency_id | integer | required |
title | string | required |
description | string | required |
start_date | date | required |
end_date | date | optional |
goal, link, address, tags | string | optional |
latitude, longitude | numeric | optional |
expected_attendance | integer | optional |
leaderboard_type | string | optional |
GET /events/{event}
Single event with coach, files, and subscriber info.
PUT /events/{event}
Update an event.
DELETE /events/{event}
Delete an event.
Event Files
GET /events/{event}/files
List all files for an event.
POST /events/{event}/files
Upload a file to an event.
DELETE /event_files/{eventFile}
Delete a file. Returns 204.
Event Subscriptions
GET /users/{user}/events
List events the user has subscribed to.
POST /users/{user}/events/{event}/subscribe
Subscribe to an event.
POST /users/{user}/events/{event}/unsubscribe
Unsubscribe from an event.
Leaderboard
GET /events/{event}/leaderboard
Get the event leaderboard. Returns 404 if the event has no leaderboard configured.
| Query Param | Default | Description |
|---|---|---|
period | overall | overall, daily, or weekly |
date | today | YYYY-MM-DD for daily; YYYY-W## for weekly |
limit | 100 | Max entries (max 500) |
// Response 200
{
"data": [
{ "rank": 1, "user_id": 5, "name": "Jane", "score": 52340 },
...
],
"meta": {
"event_id": 1,
"period": "overall",
"leaderboard_type": "steps",
"total_participants": 128,
"my_rank": 12,
"my_score": 34500
}
}
Event Attributes
GET /event_attributes
Lookup data: event_locations, event_categories, event_frequencies.
Courses
GET /courses
Paginated list (15/page). Filter: ?subscribed, ?coach_id, ?searchword.
POST /courses
| Parameter | Type | Rules |
|---|---|---|
coach_id | integer | required |
title | string | required — max 255 |
description | string | required |
goal | string | optional |
tags | string | optional |
GET /courses/{course}
Course with coach, items, and users.
PUT /courses/{course}
Update a course.
DELETE /courses/{course}
Delete a course. Returns 204.
Course Items
GET /courses/{course}/course_items
List all items in a course, ordered by position.
POST /courses/{course}/course_items
| Parameter | Type | Rules |
|---|---|---|
title | string | required |
description | string | required |
type | string | required |
GET /courses/{course}/course_items/{item}
Show a single course item.
DELETE /courses/{course}/course_items/{item}
Delete a course item and its media. Returns 204.
POST /courses/{course}/course_items/{item}/file
Upload a file attachment to a course item.
Course Subscriptions
GET /users/{user}/courses
List courses the user has subscribed to.
POST /users/{user}/courses/{course}/subscribe
Subscribe to a course.
POST /users/{user}/courses/{course}/unsubscribe
Unsubscribe from a course.
Steps
GET /users/{user}/steps
List step records (latest first). Auth user sees own steps only.
POST /users/{user}/steps
Record steps. Updates event leaderboard if active. Awards 1 BettahPoint daily bonus if total exceeds 15,000 steps. Awards 5 BettahPoints for first 10,000 step milestone.
| Parameter | Type | Rules |
|---|---|---|
recorded_at | date | required |
count | integer | required — min:0 |
unit | string | optional — default: steps |
source | string | optional |
device | string | optional |
GET /users/{user}/steps/{step}
Show a single step record.
Distances
GET /users/{user}/distances
List distance records (latest first).
POST /users/{user}/distances
Record distance. Awards 5 BettahPoints for first 10km lifetime milestone.
| Parameter | Type | Rules |
|---|---|---|
recorded_at | date | required |
amount | numeric | required — min:0 |
unit | string | optional — km|miles (default: km) |
source | string | optional |
device | string | optional |
activity_type | string | optional |
Medications
GET /users/{user}/medications
Paginated list (50/page) with reminders.
POST /users/{user}/medications
Create a medication and auto-generate reminders.
| Parameter | Type | Rules |
|---|---|---|
title | string | required — max 255 |
start_date | date | required |
end_date | date | required — after or equal to start_date |
every | integer | required — min:1 |
unit | string | required — minutes|hours|days|weeks|months |
quantity | integer | required — min:1 |
description | string | optional — max 1000 |
GET /users/{user}/medications/{medication}
Show medication with reminders.
PUT /users/{user}/medications/{medication}
Update medication. Recreates reminders based on new schedule.
DELETE /users/{user}/medications/{medication}
Delete medication. Fails if reminders exist. Returns 204.
POST /medications/reminders/{reminder}/mark_as_taken
Mark a medication reminder as taken. Returns 204.
User Points (BettahPoints)
GET /users/{user}/points
Get the user's BettahPoints balance with breakdown by transaction type.
// Response 200
{
"data": {
"balance": 250,
"lifetime_earned": 300,
"lifetime_redeemed": 50,
"breakdown": {
"registration": 5,
"profile_completion": 2,
"daily_step_bonus": 43,
"event_award": 200
}
}
}
GET /users/{user}/points/transactions
Paginated transaction history (50/page). Filter: ?type=registration|daily_step_bonus|...
// Response 200
{
"data": [
{
"id": 42,
"type": "event_award",
"amount": 100,
"balance_after": 250,
"description": "Awarded by Coach FitLife",
"created_at": "2026-03-15T10:30:00Z",
"event": { "id": 5, "title": "Spring Challenge" },
"coach": { "id": 2, "name": "Coach FitLife" }
}
],
"links": { ... },
"meta": { ... }
}
Coach Points
GET /coaches/{coach}/points
Get the coach's point wallet balance.
// Response 200
{
"data": {
"balance": 5000,
"lifetime_earned": 10000,
"lifetime_redeemed": 0
}
}
GET /coaches/{coach}/points/transactions
Paginated transaction history. Filter: ?type=coach_purchase|event_escrow|...
POST /coaches/{coach}/points/purchase
Purchase a point bundle. Credits the coach's wallet with the bundle's points.
| Parameter | Type | Rules |
|---|---|---|
bundle_id | integer | required — must exist in point_bundles and be active |
// Response 200
{
"data": {
"id": 15,
"type": "coach_purchase",
"amount": 1000,
"balance_after": 6000,
"description": "Purchased Starter Pack (1000 points)",
"created_at": "2026-03-19T14:00:00Z"
}
}
POST /coaches/{coach}/points/award
Ad-hoc award points from coach wallet to a subscriber. Atomically debits coach and credits user.
| Parameter | Type | Rules |
|---|---|---|
user_id | integer | required — must exist |
amount | integer | required — min:1 |
event_id | integer | optional — associate with an event |
description | string | optional |
Point Bundles
GET /point-bundles
List all active point bundles available for coach purchase.
// Response 200
{
"data": [
{
"id": 1,
"name": "Starter Pack",
"points": 1000,
"price": "9.99",
"currency": "USD"
},
{
"id": 2,
"name": "Pro Pack",
"points": 5000,
"price": "39.99",
"currency": "USD"
}
]
}
Event Prizes
GET /events/{event}/prizes
List prize configuration for an event, ordered by place.
// Response 200
{
"data": [
{ "id": 1, "place": 1, "points": 500, "label": "Gold" },
{ "id": 2, "place": 2, "points": 300, "label": "Silver" },
{ "id": 3, "place": 3, "points": 100, "label": "Bronze" }
]
}
POST /events/{event}/prizes
Set prizes for an event. Replaces all existing prizes. Escrows total from the coach's wallet.
| Parameter | Type | Rules |
|---|---|---|
prizes | array | required — min 1 item |
prizes.*.place | integer | required — min:1 |
prizes.*.points | integer | required — min:1 |
prizes.*.label | string | optional — e.g., "Gold", "Silver" |
// Request body
{
"prizes": [
{ "place": 1, "points": 500, "label": "Gold" },
{ "place": 2, "points": 300, "label": "Silver" },
{ "place": 3, "points": 100, "label": "Bronze" }
]
}
PUT /events/{event}/prizes
Update prizes. Adjusts escrow difference (additional debit or partial refund).
POST /events/{event}/prizes/distribute
Distribute escrowed prizes to leaderboard winners after the event has ended. Returns 422 if the event has not ended yet.
// Response 200
{
"message": "Prizes distributed successfully."
}
Partner Businesses
GET /partner-businesses
List all active partner businesses with their active offers.
// Response 200
{
"data": [
{
"id": 1,
"name": "Amazon",
"description": "Online marketplace",
"logo": "https://storage.example.com/logos/amazon.png",
"website": "https://amazon.com",
"is_active": true,
"offers": [
{
"id": 1,
"name": "$10 Gift Card",
"category": "gift_card",
"points_cost": 2000,
"value_description": "$10 Amazon Gift Card",
"in_stock": true
}
]
}
]
}
GET /partner-businesses/{partnerBusiness}
Show a partner business with all active offers.
Redemption Offers
gift_card — Digital codes delivered in-app/email •
discount — Discount codes for partner stores •
merchandise — Digital receipt/voucher to present at partner location
GET /redemption-offers
Browse all active offers (paginated, 50/page).
| Query Param | Description |
|---|---|
category | Filter: gift_card, discount, or merchandise |
partner_business_id | Filter by specific partner |
// Response 200
{
"data": [
{
"id": 1,
"name": "$10 Amazon Gift Card",
"category": "gift_card",
"points_cost": 2000,
"value_description": "$10 Amazon Gift Card",
"monetary_value": "10.00",
"image": "https://storage.example.com/offers/amazon-10.png",
"in_stock": true,
"terms": "Valid for 12 months from redemption date.",
"partner_business": {
"id": 1,
"name": "Amazon"
}
}
]
}
GET /redemption-offers/{redemptionOffer}
Show full offer details with partner business info.
Redemptions
points_cost is deducted from the user's balance.GET /users/{user}/redemptions
User's redemption history (paginated, 50/page).
POST /users/{user}/redemptions
Redeem an offer. Deducts points and generates a redemption code/receipt.
| Parameter | Type | Rules |
|---|---|---|
redemption_offer_id | integer | required — must exist and be active |
// Response 201
{
"data": {
"id": 1,
"points_spent": 2000,
"status": "completed",
"code": "BPR-A1B2C3D4",
"verification_token": "uuid-token",
"redeemed_at": "2026-03-19T15:00:00Z",
"expires_at": "2027-03-19T15:00:00Z",
"offer": {
"id": 1,
"name": "$10 Amazon Gift Card",
"category": "gift_card",
"partner_business": {
"id": 1,
"name": "Amazon"
}
}
}
}
GET /users/{user}/redemptions/{redemption}
Show full redemption details with offer and partner info, including code and verification token.
Point Transaction Types Reference
| Type | Direction | Description |
|---|---|---|
registration | +user | Awarded on account registration |
profile_completion | +user | Awarded when profile is fully completed |
first_steps_milestone | +user | First time reaching 10,000 lifetime steps |
first_transaction | +user | First payment transaction completed |
daily_step_bonus | +user | Daily bonus for exceeding step threshold |
subscription_payment | +user | Points for subscription payment |
event_award | +user / -coach | Coach awards points to subscriber |
coach_purchase | +coach | Coach purchases a point bundle |
event_escrow | -coach | Points escrowed for event prizes |
event_escrow_release | +user | Escrowed points distributed to winner |
event_escrow_refund | +coach | Unclaimed escrow returned to coach |
redemption | -user | Points spent on a redemption offer |
admin_adjustment | ± | Manual adjustment by admin |