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"]
    }
}
CodeMeaning
200Success
201Created
204No Content (successful delete)
401Unauthenticated
403Forbidden
404Not Found
410Gone (expired resource)
422Validation Error
500Server Error

Auth

POST /login Public

Authenticate a user and receive an API token.

ParameterTypeRules
usernamestringrequired — email or phone number
passwordstringrequired
// 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.

ParameterTypeRules
firstnamestringrequired
lastnamestringrequired
emailstringrequired — unique
passwordstringrequired — confirmed, min:8
password_confirmationstringrequired
date_of_birthdaterequired
genderstringrequired — male|female
country_codestringrequired
nicknamestringoptional
occupationstringoptional

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.

ParameterTypeRules
usernamestringrequired — email or phone

POST /password_reset/verify_code Public

Verify the OTP code.

ParameterTypeRules
usernamestringrequired
codeintegerrequired — 6 digits

POST /password_reset/new_password Public

Set a new password after OTP verification.

ParameterTypeRules
usernamestringrequired
passwordstringrequired — confirmed
password_confirmationstringrequired

Users

All user endpoints require Auth Required.

GET /users

Paginated list of users (50 per page).

POST /users

Create a user (admin use).

ParameterTypeRules
emailstringrequired — unique
firstnamestringrequired
lastnamestringrequired
genderstringrequired — male|female
country_codestringrequired
date_of_birthdaterequired
passwordstringrequired — confirmed
nicknamestringoptional
occupationstringoptional
national_idstringoptional — 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.

ParameterTypeRules
event_remindersbooleanoptional
sms_notificationsbooleanoptional
push_notificationsbooleanoptional
email_notificationsbooleanoptional
newsletter_subscriptionbooleanoptional
marketing_sms_notificationsbooleanoptional
marketing_email_notificationsbooleanoptional

Medical Info

PUT /users/{user}/medical_info

Update medical information.

ParameterTypeRules
heightnumericoptional
weightnumericoptional
allergiesstringoptional
blood_typestringoptional
medicationstringoptional
known_ailmentsstringoptional
favorite_sportstringoptional

User Phones

GET /users/{user}/phones

Paginated list (50/page).

POST /users/{user}/phones

ParameterTypeRules
typestringrequired
numberstringrequired — unique
labelstringoptional
is_defaultbooleanoptional
country_codestringoptional
has_whatsappbooleanoptional

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

ParameterTypeRules
typestringrequired — home|work|other
street1stringrequired
citystringrequired
statestringrequired
postal_codestringrequired
country_codestringrequired
street2stringoptional
labelstringoptional
is_defaultbooleanoptional

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

Coach types: 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

ParameterTypeRules
user_idintegerrequired
namestringrequired
emailstringrequired — unique
descriptionstringrequired
addressstringrequired
phonestringrequired — unique
tagsstringoptional
secondary_phonestringoptional
x, tiktok, website, youtube, facebook, linkedin, instagramstringoptional — 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 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

Only organization type coaches can send invitations. Invitations expire after 7 days.

GET /coaches/{coach}/invitations

List all invitations for a coach.

POST /coaches/{coach}/invitations

Send an invitation.

ParameterTypeRules
emailstringrequired without phone
phonestringrequired without email
rolestringrequired — 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 ParamDescription
subscribedFilter to user's subscribed events only
periodupcoming, ongoing, or past
coach_idFilter by coach
event_type_idFilter by event type
event_category_idFilter by category
event_frequency_idFilter by frequency
locationWildcard search on address
searchwordWildcard search on title, description, tags
start_date / end_dateDate range filter

POST /events

ParameterTypeRules
coach_idintegerrequired
created_byintegerrequired
event_type_idintegerrequired
event_category_idintegerrequired
event_frequency_idintegerrequired
titlestringrequired
descriptionstringrequired
start_datedaterequired
end_datedateoptional
goal, link, address, tagsstringoptional
latitude, longitudenumericoptional
expected_attendanceintegeroptional
leaderboard_typestringoptional

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 ParamDefaultDescription
periodoveralloverall, daily, or weekly
datetodayYYYY-MM-DD for daily; YYYY-W## for weekly
limit100Max 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

ParameterTypeRules
coach_idintegerrequired
titlestringrequired — max 255
descriptionstringrequired
goalstringoptional
tagsstringoptional

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

ParameterTypeRules
titlestringrequired
descriptionstringrequired
typestringrequired

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.

ParameterTypeRules
recorded_atdaterequired
countintegerrequired — min:0
unitstringoptional — default: steps
sourcestringoptional
devicestringoptional

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.

ParameterTypeRules
recorded_atdaterequired
amountnumericrequired — min:0
unitstringoptional — km|miles (default: km)
sourcestringoptional
devicestringoptional
activity_typestringoptional

Medications

GET /users/{user}/medications

Paginated list (50/page) with reminders.

POST /users/{user}/medications

Create a medication and auto-generate reminders.

ParameterTypeRules
titlestringrequired — max 255
start_datedaterequired
end_datedaterequired — after or equal to start_date
everyintegerrequired — min:1
unitstringrequired — minutes|hours|days|weeks|months
quantityintegerrequired — min:1
descriptionstringoptional — 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)

Automatic point awards: Registration (5 pts), Profile Completion (2 pts), First 10k Steps (5 pts), First 10km Distance (5 pts), Daily Step Bonus 15k+ (1 pt), First Transaction (5 pts), Subscription Payment (2 pts). All amounts configurable via admin settings.

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

Coaches purchase point bundles, store them in their wallet, and award them to subscribers — either ad-hoc or as event prizes.

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.

ParameterTypeRules
bundle_idintegerrequired — 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.

ParameterTypeRules
user_idintegerrequired — must exist
amountintegerrequired — min:1
event_idintegeroptional — associate with an event
descriptionstringoptional

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

Escrow flow: When prizes are configured, the total point value is debited from the coach's wallet and held in escrow. After the event ends, prizes are distributed to leaderboard winners. Unclaimed prizes (e.g., fewer participants than prize slots) are refunded to the coach.

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.

ParameterTypeRules
prizesarrayrequired — min 1 item
prizes.*.placeintegerrequired — min:1
prizes.*.pointsintegerrequired — min:1
prizes.*.labelstringoptional — 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

Categories: 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 ParamDescription
categoryFilter: gift_card, discount, or merchandise
partner_business_idFilter 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

Users must meet the minimum redemption threshold (default: 1,000 points) to redeem offers. The offer's 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.

ParameterTypeRules
redemption_offer_idintegerrequired — 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

TypeDirectionDescription
registration+userAwarded on account registration
profile_completion+userAwarded when profile is fully completed
first_steps_milestone+userFirst time reaching 10,000 lifetime steps
first_transaction+userFirst payment transaction completed
daily_step_bonus+userDaily bonus for exceeding step threshold
subscription_payment+userPoints for subscription payment
event_award+user / -coachCoach awards points to subscriber
coach_purchase+coachCoach purchases a point bundle
event_escrow-coachPoints escrowed for event prizes
event_escrow_release+userEscrowed points distributed to winner
event_escrow_refund+coachUnclaimed escrow returned to coach
redemption-userPoints spent on a redemption offer
admin_adjustment±Manual adjustment by admin