Sara777 API

Token-based REST API for the mobile app. Every response is JSON and uses the same envelope. Authentication is a Sanctum bearer token returned by register and login.

Base URL https://dpbossapp.io/api/v1

The OTP master switch

A single admin setting (Settings → OTP → “OTP Verification Enabled”) changes how two flows behave. Read GET /app-config at app start and branch on data.otp.enabled — never hard-code either flow.

This server right now: OTP is ON — registration is otp_verification, forgot-password is otp_verification.
When OTP is ON
  • Register is two steps: POST /auth/register sends an SMS OTP and returns a verification_id; the account is created only by POST /auth/register/verify-otp.
  • Forgot password works: POST /auth/forgot-password → POST /auth/forgot-password/verify-otp → POST /auth/reset-password.
  • POST /auth/resend-otp is available for both flows.
When OTP is OFF
  • Register is one step: POST /auth/register creates the account and returns the access token straight away. No SMS is sent and no verification_id is returned.
  • Forgot password is unavailable: every forgot-password / verify / reset endpoint answers 403 with error_code OTP_DISABLED. Hide the “Forgot password?” link.
  • POST /auth/resend-otp also answers 403 OTP_DISABLED.
  • An authenticated user can still change their password with POST /auth/change-password, since the current password is proof enough.

Auth Flows

The exact call sequence for each case. Read GET /app-config first and pick the branch from data.flows.

Registration — OTP ON

1
POST /auth/register
Send name, mobile, password, password_confirmation (+ optional email and device fields). Response: otp_required: true and a verification_id. No account exists yet.
2
POST /auth/register/verify-otp
Send verification_id + otp. The account is created and a token is returned. Optionally re-send the device fields here.
↻
POST /auth/resend-otp
If the SMS does not arrive. Respect resend_available_in_seconds before enabling the button.

Registration — OTP OFF

1
POST /auth/register
Same request body. The account is created immediately and the response carries otp_required: false plus the token. Skip the OTP screen entirely.

Forgot Password — OTP ON

1
POST /auth/forgot-password
Send the registered mobile. Returns a verification_id.
2
POST /auth/forgot-password/verify-otp
Send verification_id + otp. Returns a single-use reset_token valid for 15 minutes.
3
POST /auth/reset-password
Send reset_token + password + password_confirmation. All existing tokens are revoked, so send the user back to login.

Forgot Password — OTP OFF

×
Not available
Every forgot-password endpoint answers 403 with error_code: OTP_DISABLED. Hide the entry point in the UI (check data.flows.forgot_password === 'disabled'). A signed-in user can still use POST /auth/change-password, and an admin can generate a new password from the panel.

Request & Response Format

Every endpoint speaks JSON and returns the same envelope, so one parser handles the whole API.

Required headers

HeaderValue
Accept application/json (required — without it Laravel may answer with HTML)
Content-Type application/json
Authorization Bearer {token} (only on authenticated endpoints)

Success envelope

{
    "success": true,
    "message": "Human-readable text, safe to show in the UI.",
    "data": "{ ... }  // present when the endpoint returns a payload"
}

Error envelope

{
    "success": false,
    "message": "Human-readable text, safe to show in the UI.",
    "error_code": "MACHINE_READABLE_CODE",
    "errors": "{ \"field\": [\"message\"] }  // only on 422 validation failures"
}

Authentication

  • Register and login both return data.token. Send it on every protected call as Authorization: Bearer {token}.
  • Tokens do not expire on a timer. They are revoked by logout, logout-all, a password reset, or the admin deactivating or deleting the account.
  • A revoked token returns 401 UNAUTHENTICATED; a deactivated account returns 403 ACCOUNT_INACTIVE. Treat both as "go back to the login screen".
  • Store the token in secure storage (iOS Keychain / Android EncryptedSharedPreferences), never in plain preferences or a log.

Mobile number format

  • Canonical form is 10 digits starting with 6–9, e.g. 9876543210.
  • The server strips separators and a leading +91, 91 or 0 before validating, so +91 98765-43210 is accepted and stored as 9876543210.

Error Codes

Branch on error_code, never on the message text — messages may be reworded.

error_codeHTTPMeaning & what the app should do
VALIDATION_ERROR 422 One or more fields failed validation. Read the errors object for per-field messages.
INVALID_CREDENTIALS 401 Wrong mobile number or password. Deliberately the same message for both so registered numbers cannot be probed.
UNAUTHENTICATED 401 Missing, malformed or revoked bearer token. Send the user back to login.
ACCOUNT_INACTIVE 403 The admin deactivated this account. All its tokens were revoked; message carries the reason.
OTP_DISABLED 403 OTP is switched off in the admin panel and the requested flow needs it.
OTP_INVALID 422 Wrong code. attempts_remaining tells you how many tries are left.
OTP_EXPIRED 410 The code aged out. Start the flow again.
OTP_MAX_ATTEMPTS 429 Too many wrong codes. The verification was destroyed; request a fresh OTP.
OTP_COOLDOWN 429 Asked for a new OTP too soon. retry_after holds the seconds to wait.
OTP_RESEND_LIMIT 429 Resend limit for this verification reached. Restart the flow.
OTP_SEND_FAILED 502 The SMS gateway rejected or could not take the message. Offer a retry.
OTP_ALREADY_VERIFIED 409 This verification_id was already confirmed.
OTP_PURPOSE_MISMATCH 422 A registration verification_id was used on a forgot-password endpoint, or vice versa.
VERIFICATION_NOT_FOUND 404 Unknown or already-consumed verification_id.
RESET_TOKEN_INVALID 422 The reset_token is wrong or has already been used.
RESET_TOKEN_EXPIRED 422 The reset_token is older than 15 minutes. Verify the OTP again.
USER_NOT_FOUND 404 No account is registered with that mobile number.
MOBILE_TAKEN 409 The number was registered by someone else while the OTP was in flight.
EMAIL_TAKEN 409 The email was taken by another account while the OTP was in flight.
TOO_MANY_ATTEMPTS 429 Login throttle tripped (5 failures per mobile+IP, 5-minute lockout).
MAINTENANCE_MODE 503 The admin put the API in maintenance mode. Only /app-config stays reachable.
ENDPOINT_NOT_FOUND 404 Wrong URL or HTTP method.
SERVER_ERROR 500 Unexpected server fault. Details are only included while APP_DEBUG is on.

Validation error shape (422)

{
    "success": false,
    "message": "Enter a valid 10-digit Indian mobile number.",
    "error_code": "VALIDATION_ERROR",
    "errors": {
        "mobile": [
            "Enter a valid 10-digit Indian mobile number."
        ],
        "password": [
            "The password field must be at least 8 characters."
        ]
    }
}

message is the first error, ready to show in a toast. errors maps each field to its messages for inline display.

App Config

Call this first, on every app launch. It tells the client which auth flows are live.

Get App Config
GET /api/v1/app-config
Public Rate limit: 60 / minute

Returns the OTP switch state, the flow the client should use, Firebase client keys, version gating and the maintenance flag. This endpoint stays reachable during maintenance mode.

Parameters

None.

cURL

curl -X GET 'https://dpbossapp.io/api/v1/app-config' \
  -H 'Accept: application/json'

Responses

200 Success
{
    "success": true,
    "message": "App configuration fetched successfully.",
    "data": {
        "app": {
            "name": "Sara777",
            "tagline": "Admin Panel",
            "support_email": "support@sara777.test",
            "support_mobile": ""
        },
        "otp": {
            "enabled": true,
            "length": 6,
            "expiry_minutes": 10,
            "resend_cooldown_seconds": 60,
            "max_resend": 3,
            "max_verify_attempts": 5,
            "test_mode": false
        },
        "flows": {
            "registration": "otp_verification",
            "forgot_password": "otp_verification"
        },
        "firebase": {
            "enabled": true,
            "apiKey": "AIza...",
            "authDomain": "your-app.firebaseapp.com",
            "projectId": "your-app",
            "storageBucket": "your-app.appspot.com",
            "messagingSenderId": "1234567890",
            "appId": "1:1234567890:android:abcdef",
            "measurementId": "",
            "vapidKey": ""
        },
        "version": {
            "android": "1.0.0",
            "ios": "1.0.0",
            "force_update": false
        },
        "maintenance": {
            "enabled": false,
            "message": ""
        }
    }
}

Notes

  • flows.registration is "otp_verification" or "direct".
  • flows.forgot_password is "otp_verification" or "disabled".

Possible error codes

MAINTENANCE_MODE is never returned here.

Markets & Games

The game catalogue: markets, their timings, results, payout rates and the panna lookups. All public, so the app can render its home screen before the user signs in.

List Markets
GET /api/v1/markets
Public Rate limit: 120 / minute

Every active market for one engine, with its open and close times, whether each session is still taking bids, and the result for the current gaming day. One endpoint covers all three engines -- pass `engine` to pick which.

Parameters — sent as query string

Parameter Type Required Validation Description
engine string Optional nullable, in:main,starline,gali_disawar Which game engine to list. Defaults to main.
Example: main

Responses

200 Success
{
    "success": true,
    "message": "Markets fetched successfully.",
    "data": {
        "engine": "main",
        "gaming_date": "2026-10-13",
        "betting_enabled": true,
        "markets": [
            {
                "id": 4,
                "name": "Kalyan",
                "slug": "kalyan",
                "engine": "main",
                "open_time": "04:00 PM",
                "close_time": "06:00 PM",
                "status": "open",
                "accepts_open_bids": true,
                "accepts_close_bids": true,
                "closed_reason": null,
                "result": {
                    "date": "2026-10-13",
                    "open_panna": "128",
                    "open_digit": "1",
                    "close_panna": "***",
                    "close_digit": "*",
                    "display": "128-1*-***"
                }
            }
        ]
    }
}

Notes

  • status is one of: open (both sessions), close_only (open time has passed), finished (close time has passed), holiday (market shut today), suspended (admin paused it), closed (betting switched off globally).
  • Drive the bid buttons from accepts_open_bids / accepts_close_bids, not from the times -- they already account for the holiday, pause and global switches.
  • gaming_date is the betting day, which only rolls over at the configured time (06:00 by default). Before that the previous day results are still shown.
  • Undeclared results come back as *** and *, ready to display as-is.

Possible error codes

VALIDATION_ERROR MAINTENANCE_MODE
Get One Market
GET /api/v1/markets/{slug}
Public Rate limit: 120 / minute

A single market in the same shape as the list entry. Answers 404 if the market is inactive.

Parameters — sent in the URL

Parameter Type Required Validation Description
slug path string Required required, must be an active market Path parameter -- the market slug from the list.
Example: kalyan

Responses

200 Success
{
    "success": true,
    "message": "Market fetched successfully.",
    "data": {
        "market": {
            "id": 4,
            "name": "Kalyan",
            "slug": "kalyan",
            "status": "open"
        }
    }
}

Possible error codes

NOT_FOUND MAINTENANCE_MODE
Market Result Chart
GET /api/v1/markets/{slug}/chart
Public Rate limit: 120 / minute

Declared results for a market, newest first, for the chart screen.

Parameters — sent as query string

Parameter Type Required Validation Description
slug path string Required required Path parameter -- the market slug.
Example: kalyan
days integer Optional nullable, integer, min:1, max:365 How far back to read. Defaults to 60. Query string.
Example: 60

Responses

200 Success
{
    "success": true,
    "message": "Chart fetched successfully.",
    "data": {
        "market": {
            "id": 4,
            "name": "Kalyan",
            "slug": "kalyan",
            "engine": "main"
        },
        "results": [
            {
                "date": "2026-10-13",
                "open_panna": "128",
                "open_digit": 1,
                "close_panna": "460",
                "close_digit": 0,
                "jodi": "10",
                "display": "128-10-460"
            }
        ]
    }
}

Possible error codes

VALIDATION_ERROR NOT_FOUND MAINTENANCE_MODE
Game Rates
GET /api/v1/game-rates
Public Rate limit: 120 / minute

Bid types and their payouts, plus the stake limits the bid screen must enforce.

Parameters — sent as query string

Parameter Type Required Validation Description
engine string Optional nullable, in:main,starline,gali_disawar Limit to one engine. Omit for all of them.
Example: main

Responses

200 Success
{
    "success": true,
    "message": "Game rates fetched successfully.",
    "data": {
        "rates": [
            {
                "code": "single",
                "name": "Single Digit",
                "engine": "main",
                "requires_session": true,
                "bid_amount": 10,
                "win_amount": 95,
                "label": "10 ka 95"
            }
        ],
        "limits": {
            "min_bid_amount": 10,
            "max_bid_amount": 10000,
            "max_bids_per_submission": 100
        }
    }
}

Notes

  • requires_session marks the bets placed against the open or close side. Jodi and the sangam bets need both results, so they carry no session.
  • Payout scales with the stake: at "10 ka 95", a 50 stake returns 475.

Possible error codes

VALIDATION_ERROR MAINTENANCE_MODE
Panna Lookup
GET /api/v1/panna
Public Rate limit: 120 / minute

The panna reference list, grouped by type. Used by the bulk bid screens to expand a shorthand selection into the actual numbers. With no filters it returns all 220.

Parameters — sent as query string

Parameter Type Required Validation Description
types[] string Optional nullable, array, each in:sp,dp,tp Repeat the key to pass several, e.g. types[]=sp&types[]=dp. Defaults to all three.
Example: sp
digits[] integer Optional nullable, array, each integer 0-9 Keep only pannas reducing to these digits.
Example: 1

Responses

200 Success
{
    "success": true,
    "message": "Panna numbers fetched successfully.",
    "data": {
        "total": 120,
        "pannas": {
            "sp": [
                {
                    "panna": "128",
                    "digit": 1
                },
                {
                    "panna": "137",
                    "digit": 1
                }
            ]
        }
    }
}

Notes

  • There are 220 pannas in total: 120 single, 90 double and 10 triple.
  • Panna digits ascend, with 0 ranking last because it stands for 10. So 128 and 100 are valid pannas and 821 is not.
  • The digit is the last digit of the sum: 1 + 2 + 8 = 11, so 128 reduces to 1.

Possible error codes

VALIDATION_ERROR MAINTENANCE_MODE
Digit Helper
GET /api/v1/panna/digits
Public Rate limit: 120 / minute

The digits 0-9 filtered to odd, even or all, for the odd/even quick-pick.

Parameters — sent as query string

Parameter Type Required Validation Description
option string Optional nullable, in:odd,even,all Defaults to all.
Example: odd

Responses

200 Success
{
    "success": true,
    "message": "Digits fetched successfully.",
    "data": {
        "option": "odd",
        "digits": [
            1,
            3,
            5,
            7,
            9
        ]
    }
}

Possible error codes

VALIDATION_ERROR MAINTENANCE_MODE

Bidding

Placing bets and reading them back. One submission is all-or-nothing: every bid in it is validated first, then the whole lot is stored and charged as a single wallet debit. A bad bid anywhere in the list means nothing is stored and the wallet is untouched.

Place Bids
POST /api/v1/bids
Bearer token required Rate limit: 60 / minute

Takes one or more bids for a single market. Send the whole screenful in one call rather than one request per bid. `session` is required for games that are played per session (single digit and the pannas) and must be omitted for jodi and the sangams, which are decided by both results and therefore close when the open session closes.

Parameters — JSON body

Parameter Type Required Validation Description
market string Required required, must be an existing market slug The market slug, from GET /markets.
Example: kalyan
bids array Required required, array, min:1, max per the Max Bids per Submission setting (100 by default) The bids to place. All of them must be for the market named above.
Example: [ { ... } ]
bids[].game_type string Required required, must be an active game on this market engine The game code from GET /game-rates, for example single, jodi, single_panna, half_sangam.
Example: single_panna
bids[].bid_number string Required required, shape depends on the game -- see the notes below The number staked. Sent as a string so leading zeros survive.
Example: 123
bids[].amount number Required required, numeric, between the Minimum Bid and Maximum Bid settings The stake for this one bid. Read the current limits from GET /app-config rather than hard-coding them.
Example: 50
bids[].session string Sometimes nullable, in:open,close -- required for single digit and the pannas on a main market Which side of the market this bid is for. Omit it for jodi, half sangam and full sangam.
Example: open

Example request

{
    "market": "kalyan",
    "bids": "[ { ... } ]",
    "bids[].game_type": "single_panna",
    "bids[].bid_number": "123",
    "bids[].amount": 50,
    "bids[].session": "open"
}

cURL

curl -X POST 'https://dpbossapp.io/api/v1/bids' \
  -H 'Accept: application/json' \
  -H 'Content-Type: application/json' \
  -H 'Authorization: Bearer YOUR_TOKEN' \
  -d '{"market":"kalyan","bids":"[ { ... } ]","bids[].game_type":"single_panna","bids[].bid_number":"123","bids[].amount":50,"bids[].session":"open"}'

Responses

201 Placed
{
    "success": true,
    "message": "2 bids placed successfully.",
    "data": {
        "bids": [
            {
                "id": 811,
                "engine": "main",
                "market": {
                    "slug": "kalyan",
                    "name": "Kalyan"
                },
                "game_type": "single",
                "game_name": "Single Digit",
                "session": "open",
                "bid_number": "5",
                "amount": 100,
                "status": "pending",
                "win_amount": 0,
                "result_date": "2026-10-19",
                "settled_at": null,
                "created_at": "2026-10-19T06:32:10+00:00"
            }
        ],
        "total_amount": 150,
        "balance": 850
    }
}
422 One of the bids was rejected
{
    "success": false,
    "message": "Bid 2: 133 is a double panna, not a single panna.",
    "error_code": "BID_NUMBER_INVALID",
    "bid_index": 1
}

Notes

  • single -- one digit, 0 to 9. Example: 5
  • jodi -- two digits, 00 to 99. Example: 57
  • single_panna / double_panna / triple_panna -- a three digit panna that really exists and is of that type. 123 is a single panna and is refused as a double. Use GET /panna to list the valid ones.
  • half_sangam -- a panna and a digit, either way round: "123-7" is open panna with close digit, "3-457" is open digit with close panna.
  • full_sangam -- open panna and close panna: "123-457".

Possible error codes

VALIDATION_ERROR BETTING_DISABLED BETTING_BLOCKED MARKET_UNAVAILABLE MARKET_CLOSED GAME_TYPE_INVALID SESSION_REQUIRED BID_NUMBER_INVALID AMOUNT_TOO_LOW AMOUNT_TOO_HIGH TOO_MANY_BIDS NO_BIDS INSUFFICIENT_BALANCE UNAUTHENTICATED
My Bids
GET /api/v1/bids
Bearer token required Rate limit: 120 / minute

The signed-in player's own bids, newest first, with a summary over whatever the filters select. A bid stays `pending` until the result it depends on is declared, then becomes `won` or `lost` by itself.

Parameters — sent as query string

Parameter Type Required Validation Description
engine string Optional nullable, in:main,starline,gali_disawar Limit to one engine.
Example: main
market string Optional nullable, max:60 A market slug.
Example: kalyan
status string Optional nullable, in:pending,won,lost,refunded Limit to one status.
Example: won
date string Optional nullable, date Y-m-d One gaming day.
Example: 2026-10-19
from string Optional nullable, date Y-m-d Start of a range of gaming days.
Example: 2026-10-01
to string Optional nullable, date Y-m-d End of that range.
Example: 2026-10-19
per_page integer Optional nullable, integer, min:1, max:100 Page size. Defaults to 25.
Example: 25

Responses

200 Success
{
    "success": true,
    "message": "Bids fetched successfully.",
    "data": {
        "summary": {
            "total_bids": 24,
            "total_staked": 2400,
            "total_won": 1900,
            "pending": 3
        },
        "bids": [
            {
                "id": 811,
                "bid_number": "5",
                "amount": 100,
                "status": "won",
                "win_amount": 950
            }
        ],
        "pagination": {
            "current_page": 1,
            "last_page": 1,
            "per_page": 25,
            "total": 24
        }
    }
}

Possible error codes

VALIDATION_ERROR UNAUTHENTICATED

Wallet

Balance, history, and the two ways money moves. Deposits are claims until an admin confirms them. A withdrawal leaves the wallet the moment it is raised, not when it is approved, so the same balance cannot also be staked while a payout is pending.

Wallet Balance
GET /api/v1/wallet
Bearer token required Rate limit: 120 / minute

The current balance, the two feature flags, and how many requests are still waiting.

Parameters

None.

cURL

curl -X GET 'https://dpbossapp.io/api/v1/wallet' \
  -H 'Accept: application/json' \
  -H 'Authorization: Bearer YOUR_TOKEN'

Responses

200 Success
{
    "success": true,
    "message": "Wallet fetched successfully.",
    "data": {
        "balance": 850,
        "betting_enabled": true,
        "pending_deposits": 1,
        "pending_withdrawals": 0
    }
}

Possible error codes

UNAUTHENTICATED ACCOUNT_INACTIVE
Wallet History
GET /api/v1/wallet/transactions
Bearer token required Rate limit: 120 / minute

Every movement, newest first. Each row carries `signed_amount`, negative for a debit, and `balance_after`, so a list can be rendered without branching on the type and a running balance never has to be worked out in the app.

Parameters — sent as query string

Parameter Type Required Validation Description
type string Optional nullable, in:credit,debit Money in or money out.
Example: debit
category string Optional nullable, max:30 One of: signup_bonus, deposit, withdrawal, withdrawal_reversal, bid_placed, bid_won, bid_refund, admin_credit, admin_debit.
Example: bid_placed
per_page integer Optional nullable, integer, min:1, max:100 Page size. Defaults to 25.
Example: 25

Responses

200 Success
{
    "success": true,
    "message": "Wallet history fetched successfully.",
    "data": {
        "balance": 850,
        "transactions": [
            {
                "id": 44,
                "type": "debit",
                "category": "bid_placed",
                "label": "Bid placed",
                "amount": 150,
                "signed_amount": -150,
                "balance_after": 850,
                "remark": "2 bids on Kalyan",
                "created_at": "2026-10-19T06:32:10+00:00"
            }
        ],
        "pagination": {
            "current_page": 1,
            "last_page": 1,
            "per_page": 25,
            "total": 1
        }
    }
}

Possible error codes

VALIDATION_ERROR UNAUTHENTICATED
Deposit Details
GET /api/v1/wallet/deposit-info
Bearer token required Rate limit: 120 / minute

What the pay-in screen needs. `upi_intent` is a complete upi:// string -- encode it as a QR in the app rather than shipping an image, and the code can never show a VPA the admin has since changed. The same string also deep-links straight into GPay or PhonePe.

Parameters

None.

cURL

curl -X GET 'https://dpbossapp.io/api/v1/wallet/deposit-info' \
  -H 'Accept: application/json' \
  -H 'Authorization: Bearer YOUR_TOKEN'

Responses

200 Success
{
    "success": true,
    "message": "Deposit details fetched successfully.",
    "data": {
        "upi_id": "sara777@ybl",
        "payee_name": "Sara777",
        "upi_intent": "upi://pay?pa=sara777%40ybl&pn=Sara777&cu=INR",
        "min_amount": 100,
        "max_amount": 100000,
        "auto_approved": false
    }
}

Possible error codes

UNAUTHENTICATED
Add Fund
POST /api/v1/wallet/deposit
Bearer token required Rate limit: 10 / minute

Raise an add-fund request after paying through UPI. Send it as multipart/form-data when a screenshot is attached. Read `status` on the way back rather than assuming: normally it is `pending` and the balance does not move until an admin approves, but if auto-approval is switched on it comes back `approved` with the balance already updated.

Parameters — JSON body

Parameter Type Required Validation Description
amount number Required required, numeric, between the Minimum and Maximum Deposit settings How much was paid in.
Example: 500
transaction_reference string Optional nullable, max:100 The UTR or reference from the payment app.
Example: UPI2410166789
screenshot file Optional nullable, image, jpg/jpeg/png/webp, max 5 MB Proof of payment. Stored privately and only ever read by an admin.
Example: (file)

Example request

{
    "amount": 500,
    "transaction_reference": "UPI2410166789",
    "screenshot": "(file)"
}

cURL

curl -X POST 'https://dpbossapp.io/api/v1/wallet/deposit' \
  -H 'Accept: application/json' \
  -H 'Content-Type: application/json' \
  -H 'Authorization: Bearer YOUR_TOKEN' \
  -d '{"amount":500,"transaction_reference":"UPI2410166789","screenshot":"(file)"}'

Responses

201 Submitted
{
    "success": true,
    "message": "Request submitted. Your wallet is credited once it is approved.",
    "data": {
        "request": {
            "id": 12,
            "amount": 500,
            "method": "upi",
            "transaction_reference": "UPI2410166789",
            "status": "pending",
            "admin_remark": null,
            "processed_at": null,
            "created_at": "2026-10-19T06:32:10+00:00"
        },
        "balance": 850
    }
}

Possible error codes

VALIDATION_ERROR AMOUNT_TOO_LOW AMOUNT_TOO_HIGH UNAUTHENTICATED
My Add-Fund Requests
GET /api/v1/wallet/deposits
Bearer token required Rate limit: 120 / minute

The player's own add-fund requests, newest first.

Parameters — sent as query string

Parameter Type Required Validation Description
status string Optional nullable, in:pending,approved,rejected Limit to one status.
Example: pending
per_page integer Optional nullable, integer, min:1, max:100 Page size. Defaults to 25.
Example: 25

Responses

200 Success
{
    "success": true,
    "message": "Add-fund requests fetched successfully.",
    "data": {
        "requests": [],
        "pagination": {
            "current_page": 1,
            "last_page": 1,
            "per_page": 25,
            "total": 0
        }
    }
}

Possible error codes

VALIDATION_ERROR UNAUTHENTICATED
Withdrawal Rules
GET /api/v1/wallet/withdraw-info
Bearer token required Rate limit: 120 / minute

Call this before showing the withdrawal form. If `is_open_now` is false, disable the button and show `days`, `opens_at` and `closes_at` instead of letting the request fail. `days` are ISO weekday numbers, 1 = Monday.

Parameters

None.

cURL

curl -X GET 'https://dpbossapp.io/api/v1/wallet/withdraw-info' \
  -H 'Accept: application/json' \
  -H 'Authorization: Bearer YOUR_TOKEN'

Responses

200 Success
{
    "success": true,
    "message": "Withdrawal details fetched successfully.",
    "data": {
        "min_amount": 1000,
        "max_amount_per_day": 50000,
        "max_requests_per_day": 0,
        "charge_percent": 0,
        "days": [
            1,
            2,
            3,
            4,
            5
        ],
        "opens_at": "09:00",
        "closes_at": "14:00",
        "all_day": false,
        "is_open_now": true,
        "requested_today": {
            "amount": 0,
            "count": 0
        }
    }
}

Possible error codes

UNAUTHENTICATED
Withdraw
POST /api/v1/wallet/withdraw
Bearer token required Rate limit: 10 / minute

Raise a withdrawal. The amount leaves the wallet immediately and is held until an admin pays it; the balance in the response is already reduced. If the admin rejects it, the money comes back by itself and shows in the history as a withdrawal refund.

Parameters — JSON body

Parameter Type Required Validation Description
amount number Required required, numeric, at least the Minimum Withdrawal setting, within the daily cap How much to withdraw.
Example: 2000
method string Required required, in:bank,upi,phonepe,googlepay,paytm How to be paid.
Example: phonepe
bank_account_id integer Sometimes required when method is bank, must be one of the player's own saved accounts Which saved bank account to pay into.
Example: 3
payout_handle string Sometimes required for every method other than bank, max:50 The number or UPI ID to pay on.
Example: 9876543210
user_remark string Optional nullable, max:255 A note for the admin.
Example: Please pay by evening

Example request

{
    "amount": 2000,
    "method": "phonepe",
    "bank_account_id": 3,
    "payout_handle": "9876543210",
    "user_remark": "Please pay by evening"
}

cURL

curl -X POST 'https://dpbossapp.io/api/v1/wallet/withdraw' \
  -H 'Accept: application/json' \
  -H 'Content-Type: application/json' \
  -H 'Authorization: Bearer YOUR_TOKEN' \
  -d '{"amount":2000,"method":"phonepe","bank_account_id":3,"payout_handle":"9876543210","user_remark":"Please pay by evening"}'

Responses

201 Requested
{
    "success": true,
    "message": "Withdrawal requested. The amount is held until it is paid.",
    "data": {
        "request": {
            "id": 7,
            "amount": 2000,
            "method": "phonepe",
            "payout_handle": "9876543210",
            "status": "pending",
            "created_at": "2026-10-19T06:32:10+00:00"
        },
        "balance": 3000
    }
}

Possible error codes

VALIDATION_ERROR WITHDRAWAL_CLOSED AMOUNT_TOO_LOW DAILY_LIMIT_REACHED DAILY_COUNT_REACHED INSUFFICIENT_BALANCE UNAUTHENTICATED
My Withdrawals
GET /api/v1/wallet/withdrawals
Bearer token required Rate limit: 120 / minute

The player's own withdrawal requests, newest first. `paid` means the admin has sent the money.

Parameters — sent as query string

Parameter Type Required Validation Description
status string Optional nullable, in:pending,approved,rejected,paid Limit to one status.
Example: pending
per_page integer Optional nullable, integer, min:1, max:100 Page size. Defaults to 25.
Example: 25

Responses

200 Success
{
    "success": true,
    "message": "Withdrawal requests fetched successfully.",
    "data": {
        "requests": [],
        "pagination": {
            "current_page": 1,
            "last_page": 1,
            "per_page": 25,
            "total": 0
        }
    }
}

Possible error codes

VALIDATION_ERROR UNAUTHENTICATED

Bank Accounts

The accounts a player can be paid into. Up to five; the first one saved becomes the primary automatically. Account numbers are always returned masked -- only the last four digits.

List Bank Accounts
GET /api/v1/bank-accounts
Bearer token required Rate limit: 120 / minute

All saved accounts, the primary one first.

Parameters

None.

cURL

curl -X GET 'https://dpbossapp.io/api/v1/bank-accounts' \
  -H 'Accept: application/json' \
  -H 'Authorization: Bearer YOUR_TOKEN'

Responses

200 Success
{
    "success": true,
    "message": "Bank accounts fetched successfully.",
    "data": {
        "accounts": [
            {
                "id": 3,
                "account_holder": "Ramesh Patel",
                "account_number_masked": "XXXXXXXX9012",
                "ifsc_code": "HDFC0001234",
                "bank_name": "HDFC Bank",
                "branch": null,
                "is_primary": true,
                "created_at": "2026-10-19T06:32:10+00:00"
            }
        ]
    }
}

Possible error codes

UNAUTHENTICATED
Add Bank Account
POST /api/v1/bank-accounts
Bearer token required Rate limit: 120 / minute

Save an account. The same account number cannot be saved twice on one profile.

Parameters — JSON body

Parameter Type Required Validation Description
account_holder string Required required, max:100 Name as it appears on the account.
Example: Ramesh Patel
account_number string Required required, digits only, min:6, max:30, unique per player The account number.
Example: 123456789012
ifsc_code string Required required, 4 letters + 0 + 6 alphanumerics IFSC of the branch. Upper-cased automatically.
Example: HDFC0001234
bank_name string Required required, max:100 Name of the bank.
Example: HDFC Bank
branch string Optional nullable, max:100 Branch name.
Example: Navrangpura
is_primary boolean Optional nullable, boolean Make this the default for payouts. The first account saved becomes primary whatever this says.
Example: true

Example request

{
    "account_holder": "Ramesh Patel",
    "account_number": "123456789012",
    "ifsc_code": "HDFC0001234",
    "bank_name": "HDFC Bank",
    "branch": "Navrangpura",
    "is_primary": true
}

cURL

curl -X POST 'https://dpbossapp.io/api/v1/bank-accounts' \
  -H 'Accept: application/json' \
  -H 'Content-Type: application/json' \
  -H 'Authorization: Bearer YOUR_TOKEN' \
  -d '{"account_holder":"Ramesh Patel","account_number":"123456789012","ifsc_code":"HDFC0001234","bank_name":"HDFC Bank","branch":"Navrangpura","is_primary":true}'

Responses

201 Saved
{
    "success": true,
    "message": "Bank account saved successfully.",
    "data": {
        "account": {
            "id": 3,
            "account_number_masked": "XXXXXXXX9012",
            "is_primary": true
        }
    }
}

Possible error codes

VALIDATION_ERROR TOO_MANY_ACCOUNTS UNAUTHENTICATED
Update Bank Account
PUT /api/v1/bank-accounts/{id}
Bearer token required Rate limit: 120 / minute

Change a saved account. Takes the same fields as adding one.

Parameters — JSON body

Parameter Type Required Validation Description
id path integer Required required, must belong to the signed-in player Path parameter -- the account id.
Example: 3

Responses

200 Updated
{
    "success": true,
    "message": "Bank account updated successfully.",
    "data": {
        "account": {
            "id": 3
        }
    }
}

Possible error codes

VALIDATION_ERROR NOT_FOUND UNAUTHENTICATED
Set Primary Account
POST /api/v1/bank-accounts/{id}/primary
Bearer token required Rate limit: 120 / minute

Make this the account payouts default to. Whichever was primary stops being so.

Parameters — JSON body

Parameter Type Required Validation Description
id path integer Required required, must belong to the signed-in player Path parameter -- the account id.
Example: 3

Responses

200 Updated
{
    "success": true,
    "message": "Primary bank account updated.",
    "data": {
        "account": {
            "id": 3,
            "is_primary": true
        }
    }
}

Possible error codes

NOT_FOUND UNAUTHENTICATED
Remove Bank Account
DELETE /api/v1/bank-accounts/{id}
Bearer token required Rate limit: 120 / minute

Remove an account. Refused while a pending withdrawal still points at it. If the primary one is removed, the next account becomes primary so the player is never left with accounts but no default.

Parameters — JSON body

Parameter Type Required Validation Description
id path integer Required required, must belong to the signed-in player Path parameter -- the account id.
Example: 3

Responses

200 Removed
{
    "success": true,
    "message": "Bank account removed successfully."
}

Possible error codes

ACCOUNT_IN_USE NOT_FOUND UNAUTHENTICATED

Content

Banners, notices and the information screens. All public, so the home screen can be drawn before anyone signs in. The text comes from Settings in the admin panel, so it changes without an app release.

Home Content
GET /api/v1/content
Public Rate limit: 120 / minute

Banners, the notices for one placement, and the support channels, in one call so the home screen does not have to make three.

Parameters — sent as query string

Parameter Type Required Validation Description
placement string Optional nullable, in:home,app,add_fund,withdraw Which screen the notices are for. Defaults to home.
Example: home

Responses

200 Success
{
    "success": true,
    "message": "Content fetched successfully.",
    "data": {
        "sliders": [
            {
                "id": 2,
                "image_url": "https://dpbossapp.io/api/v1/content/sliders/2/image",
                "link_url": null,
                "caption": "Welcome"
            }
        ],
        "notices": [
            {
                "id": 5,
                "placement": "home",
                "title": null,
                "body": "Markets are closed on Sunday.",
                "updated_at": "2026-10-19T06:32:10+00:00"
            }
        ],
        "contact": {
            "whatsapp": "919876543210",
            "telegram": null,
            "mobile": null,
            "email": null
        }
    }
}

Possible error codes

VALIDATION_ERROR MAINTENANCE_MODE
Notices
GET /api/v1/content/notices
Public Rate limit: 120 / minute

The live notices, lowest sort order first. Omit `placement` to get them all; pass one to get only that screen's.

Parameters — sent as query string

Parameter Type Required Validation Description
placement string Optional nullable, in:home,app,add_fund,withdraw Which screen the notice belongs above.
Example: add_fund

Responses

200 Success
{
    "success": true,
    "message": "Notices fetched successfully.",
    "data": {
        "notices": []
    }
}

Possible error codes

VALIDATION_ERROR MAINTENANCE_MODE
Banners
GET /api/v1/content/sliders
Public Rate limit: 120 / minute

The home screen banners, in order. Each carries a ready-made `image_url`.

Parameters

None.

cURL

curl -X GET 'https://dpbossapp.io/api/v1/content/sliders' \
  -H 'Accept: application/json'

Responses

200 Success
{
    "success": true,
    "message": "Sliders fetched successfully.",
    "data": {
        "sliders": []
    }
}

Possible error codes

MAINTENANCE_MODE
Banner Image
GET /api/v1/content/sliders/{slider}/image
Public Rate limit: 120 / minute

The banner image itself. Use the `image_url` from the list rather than building this path by hand. Answers the image bytes, not JSON, and is cached for a day. A banner the admin has switched off answers 404.

Parameters — sent in the URL

Parameter Type Required Validation Description
slider path integer Required required, must be a live banner Path parameter -- the banner id.
Example: 2

Responses

200 The image bytes
"(binary image data)"

Possible error codes

NOT_FOUND
Information Page
GET /api/v1/content/pages/{page}
Public Rate limit: 120 / minute

The text for one information screen. Plain text, with blank lines between paragraphs. Edited in the admin panel under Settings, so it changes without an app release.

Parameters — sent in the URL

Parameter Type Required Validation Description
page path string Required required, one of: terms, how-to-play, about Path parameter -- which screen.
Example: terms

Responses

200 Success
{
    "success": true,
    "message": "Page fetched successfully.",
    "data": {
        "key": "terms",
        "title": "Terms",
        "body": "By using this app you agree ..."
    }
}

Possible error codes

NOT_FOUND MAINTENANCE_MODE
Contact Details
GET /api/v1/content/contact
Public Rate limit: 120 / minute

How players reach support. Any of these may be null -- hide the button when it is.

Parameters

None.

cURL

curl -X GET 'https://dpbossapp.io/api/v1/content/contact' \
  -H 'Accept: application/json'

Responses

200 Success
{
    "success": true,
    "message": "Contact details fetched successfully.",
    "data": {
        "whatsapp": "919876543210",
        "telegram": null,
        "mobile": "9876543210",
        "email": "support@sara777.test"
    }
}

Possible error codes

MAINTENANCE_MODE

Support Messages

Messages a player sends from the contact screen, and the replies an admin writes back. A player only ever sees their own.

Send a Message
POST /api/v1/enquiries
Bearer token required Rate limit: 5 / minute

Send support a message. Name and mobile fall back to the signed-in account, so normally only `message` needs sending.

Parameters — JSON body

Parameter Type Required Validation Description
message string Required required, min:5, max:2000 What the player wants to say.
Example: My withdrawal is still pending.
name string Optional nullable, max:100 Defaults to the name on the account.
Example: Ramesh Patel
mobile string Optional nullable, max:15 Defaults to the mobile on the account.
Example: 9876543210

Example request

{
    "message": "My withdrawal is still pending.",
    "name": "Ramesh Patel",
    "mobile": "9876543210"
}

cURL

curl -X POST 'https://dpbossapp.io/api/v1/enquiries' \
  -H 'Accept: application/json' \
  -H 'Content-Type: application/json' \
  -H 'Authorization: Bearer YOUR_TOKEN' \
  -d '{"message":"My withdrawal is still pending.","name":"Ramesh Patel","mobile":"9876543210"}'

Responses

201 Sent
{
    "success": true,
    "message": "Thanks -- we have your message and will reply soon.",
    "data": {
        "enquiry": {
            "id": 9,
            "message": "My withdrawal is still pending.",
            "status": "open",
            "admin_reply": null,
            "replied_at": null,
            "created_at": "2026-10-19T06:32:10+00:00"
        }
    }
}

Possible error codes

VALIDATION_ERROR TOO_MANY_ATTEMPTS UNAUTHENTICATED
My Messages
GET /api/v1/enquiries
Bearer token required Rate limit: 120 / minute

The player's own messages, newest first. `status` moves from `open` to `replied` once an admin answers, and `admin_reply` carries what they wrote.

Parameters

None.

cURL

curl -X GET 'https://dpbossapp.io/api/v1/enquiries' \
  -H 'Accept: application/json' \
  -H 'Authorization: Bearer YOUR_TOKEN'

Responses

200 Success
{
    "success": true,
    "message": "Your messages fetched successfully.",
    "data": {
        "enquiries": [
            {
                "id": 9,
                "message": "My withdrawal is still pending.",
                "status": "replied",
                "admin_reply": "Paid this afternoon.",
                "replied_at": "2026-10-19T08:00:00+00:00",
                "created_at": "2026-10-19T06:32:10+00:00"
            }
        ],
        "pagination": {
            "current_page": 1,
            "last_page": 1,
            "per_page": 25,
            "total": 1
        }
    }
}

Possible error codes

UNAUTHENTICATED

Live Chat

One-to-one chat with support. The messages never pass through this API: they live in Firestore, so they arrive on both sides without polling. All this API does is vouch for who the player is, by handing out a short-lived Firebase custom token. See FIREBASE-CHAT.md for the Firestore shape and the security rules.

Chat Availability
GET /api/v1/chat/config
Bearer token required Rate limit: 120 / minute

Whether to show the chat screen at all. Check this before asking for a token, so a switched-off chat is a hidden button rather than a failed request.

Parameters

None.

cURL

curl -X GET 'https://dpbossapp.io/api/v1/chat/config' \
  -H 'Accept: application/json' \
  -H 'Authorization: Bearer YOUR_TOKEN'

Responses

200 Success
{
    "success": true,
    "message": "Chat configuration fetched successfully.",
    "data": {
        "enabled": true,
        "welcome_message": "Hi! How can we help you today?"
    }
}

Possible error codes

UNAUTHENTICATED
Chat Token
POST /api/v1/chat/token
Bearer token required Rate limit: 30 / minute

A Firebase custom token to sign in with, plus the Firestore paths this player may use. Sign in with signInWithCustomToken(token), then listen to messages_path ordered by created_at. The token lasts an hour -- ask for another when Firebase reports the session has gone, rather than holding one indefinitely.

Parameters

None.

cURL

curl -X POST 'https://dpbossapp.io/api/v1/chat/token' \
  -H 'Accept: application/json' \
  -H 'Authorization: Bearer YOUR_TOKEN'

Responses

200 Issued
{
    "success": true,
    "message": "Chat token issued successfully.",
    "data": {
        "token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
        "uid": "42",
        "thread_path": "chat_threads/42",
        "messages_path": "chat_threads/42/messages",
        "expires_in": 3600,
        "firebase": {
            "apiKey": "AIza...",
            "authDomain": "sara777.firebaseapp.com",
            "projectId": "sara777",
            "appId": "1:1234:web:abcd",
            "messagingSenderId": "1234"
        }
    }
}
403 Chat is switched off
{
    "success": false,
    "message": "Live chat is currently switched off.",
    "error_code": "CHAT_DISABLED"
}

Notes

  • The uid is the player's account id, and the thread is keyed by the same id. The security rules match one against the other, so a player can only ever reach their own conversation.
  • Writing a message means two writes: the message itself, and the thread summary (last_message, last_message_at, unread_for_admin). Without the second, the admin list will not show it.
  • created_at must be serverTimestamp(). The rules reject anything else, so neither side can backdate a message.
  • Messages cannot be edited or deleted by either side.

Possible error codes

CHAT_DISABLED CHAT_NOT_CONFIGURED UNAUTHENTICATED TOO_MANY_ATTEMPTS

Registration

Account creation. One step or two, depending on the OTP switch.

Register
POST /api/v1/auth/register
Public Rate limit: 10 / minute per IP

Starts registration. Validation runs the same way in both modes, so a duplicate mobile number or a weak password is rejected before any SMS is sent.

OTP ON
Nothing is written to the users table yet. An OTP is sent and the submitted data is held, encrypted, against the returned verification_id. Call /auth/register/verify-otp to finish.
OTP OFF
The account is created immediately and the response contains the access token. otp_required is false and no verification_id is returned.

Parameters — JSON body

Parameter Type Required Validation Description
name string Required required, min:2, max:100, letters / spaces / . ' - only Full name. Digits and other symbols are rejected.
Example: Maharshi Suhagiya
mobile string Required required, 10 digits starting 6-9, unique:users Indian mobile number and the login identifier. A leading +91, 91 or 0 is stripped automatically, so "+91 98765 43210" is accepted.
Example: 9876543210
email string Optional nullable, valid email, max:150, unique:users Optional. Send null or omit the key entirely.
Example: user@example.com
password string Required required, min:8, confirmed In production also requires letters + numbers and is checked against the HaveIBeenPwned breach list.
Example: Secret@123
password_confirmation string Required required, must equal password Required because of the `confirmed` rule on password.
Example: Secret@123
fcm_token string Optional max:500 Firebase Cloud Messaging registration token for this device. Stored against the account so the admin panel can push notifications to it.
Example: fZx9K2...A1b
device_type string Optional in:android,ios,web Platform the request came from.
Example: android
device_id string Optional max:150 Stable per-install identifier. Send the same value every time so one handset keeps one device record instead of creating duplicates.
Example: a1b2c3d4e5f6
device_name string Optional max:100 Human-readable device label. Also used as the access-token name.
Example: Redmi Note 13
app_version string Optional max:20 Installed app version.
Example: 1.0.0

Example request

{
    "name": "Maharshi Suhagiya",
    "mobile": "9876543210",
    "email": "user@example.com",
    "password": "Secret@123",
    "password_confirmation": "Secret@123",
    "fcm_token": "fZx9K2...A1b",
    "device_type": "android",
    "device_id": "a1b2c3d4e5f6",
    "device_name": "Redmi Note 13",
    "app_version": "1.0.0"
}

cURL

curl -X POST 'https://dpbossapp.io/api/v1/auth/register' \
  -H 'Accept: application/json' \
  -H 'Content-Type: application/json' \
  -d '{"name":"Maharshi Suhagiya","mobile":"9876543210","email":"user@example.com","password":"Secret@123","password_confirmation":"Secret@123","fcm_token":"fZx9K2...A1b","device_type":"android","device_id":"a1b2c3d4e5f6","device_name":"Redmi Note 13","app_version":"1.0.0"}'

Responses

200 OTP ON — verification required
{
    "success": true,
    "message": "An OTP has been sent to your mobile number.",
    "data": {
        "otp_required": true,
        "verification_id": "9f2c1a84-7b3e-4d51-9c8a-1e2f3a4b5c6d",
        "mobile": "9876543210",
        "purpose": "registration",
        "otp_length": 6,
        "expires_at": "2026-10-04T12:40:00+00:00",
        "expires_in_seconds": 600,
        "resend_available_in_seconds": 60,
        "resend_attempts_left": 3
    }
}
201 OTP OFF — account created
{
    "success": true,
    "message": "Registration successful.",
    "data": {
        "otp_required": false,
        "token_type": "Bearer",
        "token": "1|xZq8Lm2PwKd93nTyRv4bCsE7HgJ1aF6uOi0pYlXz",
        "user": {
            "id": 1,
            "name": "Maharshi Suhagiya",
            "mobile": "9876543210",
            "email": "user@example.com",
            "is_active": true,
            "is_mobile_verified": false,
            "mobile_verified_at": null,
            "device_type": "android",
            "app_version": "1.0.0",
            "last_login_at": "2026-10-04T12:30:00+00:00",
            "created_at": "2026-10-04T12:30:00+00:00"
        },
        "note": "OTP verification is disabled, so the account is active immediately."
    }
}

Notes

  • Branch on data.otp_required, not on the HTTP status.
  • With OTP off, is_mobile_verified is false — there was no verification step. An admin can tick it manually.
  • In Test Mode the response also carries data.otp and data.test_mode so you can develop without real SMS.

Possible error codes

VALIDATION_ERROR OTP_COOLDOWN OTP_SEND_FAILED MAINTENANCE_MODE
Verify Registration OTP
POST /api/v1/auth/register/verify-otp
Public Rate limit: 20 / minute per IP

Confirms the OTP from /auth/register and creates the account. Only called when OTP is ON.

Parameters — JSON body

Parameter Type Required Validation Description
verification_id uuid Required required, uuid The value returned by /auth/register.
Example: 9f2c1a84-7b3e-4d51-9c8a-1e2f3a4b5c6d
otp string Required required, numeric, 4-8 digits The code from the SMS. Send it as a string to preserve leading zeros.
Example: 483921
fcm_token string Optional max:500 Firebase Cloud Messaging registration token for this device. Stored against the account so the admin panel can push notifications to it.
Example: fZx9K2...A1b
device_type string Optional in:android,ios,web Platform the request came from.
Example: android
device_id string Optional max:150 Stable per-install identifier. Send the same value every time so one handset keeps one device record instead of creating duplicates.
Example: a1b2c3d4e5f6
device_name string Optional max:100 Human-readable device label. Also used as the access-token name.
Example: Redmi Note 13
app_version string Optional max:20 Installed app version.
Example: 1.0.0

Example request

{
    "verification_id": "9f2c1a84-7b3e-4d51-9c8a-1e2f3a4b5c6d",
    "otp": "483921",
    "fcm_token": "fZx9K2...A1b",
    "device_type": "android",
    "device_id": "a1b2c3d4e5f6",
    "device_name": "Redmi Note 13",
    "app_version": "1.0.0"
}

cURL

curl -X POST 'https://dpbossapp.io/api/v1/auth/register/verify-otp' \
  -H 'Accept: application/json' \
  -H 'Content-Type: application/json' \
  -d '{"verification_id":"9f2c1a84-7b3e-4d51-9c8a-1e2f3a4b5c6d","otp":"483921","fcm_token":"fZx9K2...A1b","device_type":"android","device_id":"a1b2c3d4e5f6","device_name":"Redmi Note 13","app_version":"1.0.0"}'

Responses

201 Verified and registered
{
    "success": true,
    "message": "Registration completed successfully.",
    "data": {
        "otp_required": false,
        "token_type": "Bearer",
        "token": "2|aB3cD4eF5gH6iJ7kL8mN9oP0qR1sT2uV3wX4yZ5",
        "user": {
            "id": 2,
            "name": "Maharshi Suhagiya",
            "mobile": "9876543210",
            "email": null,
            "is_active": true,
            "is_mobile_verified": true,
            "mobile_verified_at": "2026-10-04T12:33:00+00:00",
            "device_type": "android",
            "app_version": "1.0.0",
            "last_login_at": "2026-10-04T12:33:00+00:00",
            "created_at": "2026-10-04T12:33:00+00:00"
        },
        "note": "Mobile number verified successfully."
    }
}
422 Wrong code
{
    "success": false,
    "message": "The OTP you entered is incorrect. 4 attempt(s) left.",
    "error_code": "OTP_INVALID",
    "attempts_remaining": 4
}

Notes

  • Device fields sent here override whatever was sent at register time, so you can skip them on register and send them once at verify.
  • After max attempts the verification is deleted — restart from /auth/register.

Possible error codes

VALIDATION_ERROR OTP_INVALID OTP_EXPIRED OTP_MAX_ATTEMPTS OTP_ALREADY_VERIFIED OTP_PURPOSE_MISMATCH VERIFICATION_NOT_FOUND MOBILE_TAKEN EMAIL_TAKEN OTP_DISABLED

Login & Session

Password login and token lifecycle. Unaffected by the OTP switch.

Login
POST /api/v1/auth/login
Public Rate limit: 20 / minute per IP, plus 5 failures per mobile+IP then a 5-minute lockout

Exchanges mobile + password for a bearer token. The device payload is captured on every login, so the FCM token stays current without a separate call.

Parameters — JSON body

Parameter Type Required Validation Description
mobile string Required required, 10 digits starting 6-9 A +91 / 91 / 0 prefix is stripped automatically.
Example: 9876543210
password string Required required The account password.
Example: Secret@123
fcm_token string Optional max:500 Firebase Cloud Messaging registration token for this device. Stored against the account so the admin panel can push notifications to it.
Example: fZx9K2...A1b
device_type string Optional in:android,ios,web Platform the request came from.
Example: android
device_id string Optional max:150 Stable per-install identifier. Send the same value every time so one handset keeps one device record instead of creating duplicates.
Example: a1b2c3d4e5f6
device_name string Optional max:100 Human-readable device label. Also used as the access-token name.
Example: Redmi Note 13
app_version string Optional max:20 Installed app version.
Example: 1.0.0

Example request

{
    "mobile": "9876543210",
    "password": "Secret@123",
    "fcm_token": "fZx9K2...A1b",
    "device_type": "android",
    "device_id": "a1b2c3d4e5f6",
    "device_name": "Redmi Note 13",
    "app_version": "1.0.0"
}

cURL

curl -X POST 'https://dpbossapp.io/api/v1/auth/login' \
  -H 'Accept: application/json' \
  -H 'Content-Type: application/json' \
  -d '{"mobile":"9876543210","password":"Secret@123","fcm_token":"fZx9K2...A1b","device_type":"android","device_id":"a1b2c3d4e5f6","device_name":"Redmi Note 13","app_version":"1.0.0"}'

Responses

200 Success
{
    "success": true,
    "message": "Logged in successfully.",
    "data": {
        "otp_required": false,
        "token_type": "Bearer",
        "token": "3|pQ8rS9tU0vW1xY2zA3bC4dE5fG6hI7jK8lM9nO0",
        "user": {
            "id": 2,
            "name": "Maharshi Suhagiya",
            "mobile": "9876543210",
            "email": null,
            "is_active": true,
            "is_mobile_verified": true,
            "mobile_verified_at": "2026-10-04T12:33:00+00:00",
            "device_type": "android",
            "app_version": "1.0.0",
            "last_login_at": "2026-10-04T13:00:00+00:00",
            "created_at": "2026-10-04T12:33:00+00:00"
        }
    }
}
401 Wrong credentials
{
    "success": false,
    "message": "The mobile number or password is incorrect.",
    "error_code": "INVALID_CREDENTIALS"
}
403 Deactivated by admin
{
    "success": false,
    "message": "Your account has been deactivated. Please contact support.",
    "error_code": "ACCOUNT_INACTIVE"
}

Notes

  • Logging in does not revoke tokens on other devices — one token per device is the intended model.
  • Store the token securely (Keychain / EncryptedSharedPreferences), not in plain preferences.

Possible error codes

VALIDATION_ERROR INVALID_CREDENTIALS ACCOUNT_INACTIVE TOO_MANY_ATTEMPTS MAINTENANCE_MODE
Resend OTP
POST /api/v1/auth/resend-otp
Public Rate limit: 10 / minute per IP, plus the configured cooldown per verification

Issues a brand-new code for an existing verification. Works for both the registration and forgot-password flows — the purpose is taken from the verification_id. The wrong-attempt counter resets and the expiry window restarts.

Parameters — JSON body

Parameter Type Required Validation Description
verification_id uuid Required required, uuid The verification to re-send for.
Example: 9f2c1a84-7b3e-4d51-9c8a-1e2f3a4b5c6d

Example request

{
    "verification_id": "9f2c1a84-7b3e-4d51-9c8a-1e2f3a4b5c6d"
}

cURL

curl -X POST 'https://dpbossapp.io/api/v1/auth/resend-otp' \
  -H 'Accept: application/json' \
  -H 'Content-Type: application/json' \
  -d '{"verification_id":"9f2c1a84-7b3e-4d51-9c8a-1e2f3a4b5c6d"}'

Responses

200 Resent
{
    "success": true,
    "message": "A new OTP has been sent to your mobile number.",
    "data": {
        "verification_id": "9f2c1a84-7b3e-4d51-9c8a-1e2f3a4b5c6d",
        "mobile": "9876543210",
        "purpose": "registration",
        "otp_length": 6,
        "expires_at": "2026-10-04T12:50:00+00:00",
        "expires_in_seconds": 600,
        "resend_available_in_seconds": 60,
        "resend_attempts_left": 2
    }
}
429 Too soon
{
    "success": false,
    "message": "Please wait 43 second(s) before requesting another OTP.",
    "error_code": "OTP_COOLDOWN",
    "retry_after": 43
}

Notes

  • Drive the resend button countdown from data.resend_available_in_seconds, and from retry_after on a 429.
  • When resend_attempts_left hits 0 the user must restart the flow.

Possible error codes

VALIDATION_ERROR OTP_COOLDOWN OTP_RESEND_LIMIT OTP_EXPIRED VERIFICATION_NOT_FOUND OTP_SEND_FAILED OTP_DISABLED
Logout
POST /api/v1/auth/logout
Bearer token required Rate limit: 120 / minute

Revokes only the token used to make the call. Other devices stay signed in.

Parameters — JSON body

Parameter Type Required Validation Description
device_id string Optional nullable, max:150 Send the same device_id you used at login to also clear that device's FCM token, so it stops receiving push notifications.
Example: a1b2c3d4e5f6

Example request

{
    "device_id": "a1b2c3d4e5f6"
}

cURL

curl -X POST 'https://dpbossapp.io/api/v1/auth/logout' \
  -H 'Accept: application/json' \
  -H 'Content-Type: application/json' \
  -H 'Authorization: Bearer YOUR_TOKEN' \
  -d '{"device_id":"a1b2c3d4e5f6"}'

Responses

200 Success
{
    "success": true,
    "message": "Logged out successfully."
}

Possible error codes

UNAUTHENTICATED ACCOUNT_INACTIVE
Logout All Devices
POST /api/v1/auth/logout-all
Bearer token required Rate limit: 120 / minute

Revokes every token for the account and clears all stored FCM tokens.

Parameters

None.

cURL

curl -X POST 'https://dpbossapp.io/api/v1/auth/logout-all' \
  -H 'Accept: application/json' \
  -H 'Authorization: Bearer YOUR_TOKEN'

Responses

200 Success
{
    "success": true,
    "message": "Logged out from all devices."
}

Possible error codes

UNAUTHENTICATED ACCOUNT_INACTIVE

Password Reset

OTP-only recovery. Entirely gated by the admin OTP switch — check /app-config first.

Forgot Password Availability
GET /api/v1/auth/forgot-password/availability
Public Rate limit: 60 / minute

A tiny endpoint for deciding whether to render the “Forgot password?” link, if you would rather not cache the whole /app-config payload. Always answers 200.

Parameters

None.

cURL

curl -X GET 'https://dpbossapp.io/api/v1/auth/forgot-password/availability' \
  -H 'Accept: application/json'

Responses

200 OTP ON
{
    "success": true,
    "message": "Password reset is available.",
    "data": {
        "available": true,
        "reason": null
    }
}
200 OTP OFF
{
    "success": true,
    "message": "Password reset is disabled.",
    "data": {
        "available": false,
        "reason": "OTP verification is disabled by the administrator."
    }
}

Possible error codes

MAINTENANCE_MODE
Forgot Password — Send OTP
POST /api/v1/auth/forgot-password
Public Rate limit: 10 / minute per IP

Step 1 of 3. Sends a reset OTP to a registered mobile number.

OTP ON
An OTP is sent and a verification_id is returned.
OTP OFF
Returns 403 OTP_DISABLED without sending anything. There is no alternative recovery channel — an admin must reset the password from the panel.

Parameters — JSON body

Parameter Type Required Validation Description
mobile string Required required, 10 digits starting 6-9 Must belong to an existing, active account.
Example: 9876543210

Example request

{
    "mobile": "9876543210"
}

cURL

curl -X POST 'https://dpbossapp.io/api/v1/auth/forgot-password' \
  -H 'Accept: application/json' \
  -H 'Content-Type: application/json' \
  -d '{"mobile":"9876543210"}'

Responses

200 OTP sent
{
    "success": true,
    "message": "An OTP has been sent to your registered mobile number.",
    "data": {
        "otp_required": true,
        "verification_id": "4c7d2e91-8a5b-4f63-b2d1-7e8f9a0b1c2d",
        "mobile": "9876543210",
        "purpose": "forgot_password",
        "otp_length": 6,
        "expires_at": "2026-10-04T13:10:00+00:00",
        "expires_in_seconds": 600,
        "resend_available_in_seconds": 60,
        "resend_attempts_left": 3
    }
}
403 OTP switched off
{
    "success": false,
    "message": "Password reset is currently unavailable. Please contact support for help.",
    "error_code": "OTP_DISABLED"
}
404 Not registered
{
    "success": false,
    "message": "No account is registered with this mobile number.",
    "error_code": "USER_NOT_FOUND"
}

Notes

  • This endpoint does confirm whether a number is registered, which the OTP flow unavoidably reveals. It is rate limited to 10 requests per minute per IP to blunt enumeration.

Possible error codes

VALIDATION_ERROR OTP_DISABLED USER_NOT_FOUND ACCOUNT_INACTIVE OTP_COOLDOWN OTP_SEND_FAILED
Forgot Password — Verify OTP
POST /api/v1/auth/forgot-password/verify-otp
Public Rate limit: 20 / minute per IP

Step 2 of 3. On success returns a single-use reset_token valid for 15 minutes. The password is not changed yet.

Parameters — JSON body

Parameter Type Required Validation Description
verification_id uuid Required required, uuid From step 1.
Example: 4c7d2e91-8a5b-4f63-b2d1-7e8f9a0b1c2d
otp string Required required, numeric, 4-8 digits The code from the SMS.
Example: 728140

Example request

{
    "verification_id": "4c7d2e91-8a5b-4f63-b2d1-7e8f9a0b1c2d",
    "otp": "728140"
}

cURL

curl -X POST 'https://dpbossapp.io/api/v1/auth/forgot-password/verify-otp' \
  -H 'Accept: application/json' \
  -H 'Content-Type: application/json' \
  -d '{"verification_id":"4c7d2e91-8a5b-4f63-b2d1-7e8f9a0b1c2d","otp":"728140"}'

Responses

200 Verified
{
    "success": true,
    "message": "OTP verified. Use the reset_token to set a new password.",
    "data": {
        "verified": true,
        "reset_token": "KxP9mQ2rT5vY8zA1bC4dE7fG0hJ3kL6nO9pR2sU5wX8yZ1aB4cD7eF0gH3iJ6kM9",
        "reset_token_expires_in_seconds": 900
    }
}

Notes

  • reset_token is always 64 characters. Keep it in memory only — do not persist it.

Possible error codes

VALIDATION_ERROR OTP_INVALID OTP_EXPIRED OTP_MAX_ATTEMPTS OTP_PURPOSE_MISMATCH VERIFICATION_NOT_FOUND OTP_DISABLED
Reset Password
POST /api/v1/auth/reset-password
Public Rate limit: 10 / minute per IP

Step 3 of 3. Consumes the reset_token, sets the new password and revokes every existing token for the account, so all devices are signed out. The user then logs in again.

Parameters — JSON body

Parameter Type Required Validation Description
reset_token string Required required, exactly 64 characters From step 2. Single use.
Example: KxP9mQ2rT5vY8zA1bC4dE7fG0hJ3kL6nO9pR2sU5wX8yZ1aB4cD7eF0gH3iJ6kM9
password string Required required, min:8, confirmed The new password.
Example: NewSecret@456
password_confirmation string Required required, must equal password Confirmation field.
Example: NewSecret@456

Example request

{
    "reset_token": "KxP9mQ2rT5vY8zA1bC4dE7fG0hJ3kL6nO9pR2sU5wX8yZ1aB4cD7eF0gH3iJ6kM9",
    "password": "NewSecret@456",
    "password_confirmation": "NewSecret@456"
}

cURL

curl -X POST 'https://dpbossapp.io/api/v1/auth/reset-password' \
  -H 'Accept: application/json' \
  -H 'Content-Type: application/json' \
  -d '{"reset_token":"KxP9mQ2rT5vY8zA1bC4dE7fG0hJ3kL6nO9pR2sU5wX8yZ1aB4cD7eF0gH3iJ6kM9","password":"NewSecret@456","password_confirmation":"NewSecret@456"}'

Responses

200 Password reset
{
    "success": true,
    "message": "Your password has been reset successfully. Please log in again."
}
422 Token already used
{
    "success": false,
    "message": "This reset session is invalid or has already been used.",
    "error_code": "RESET_TOKEN_INVALID"
}

Possible error codes

VALIDATION_ERROR RESET_TOKEN_INVALID RESET_TOKEN_EXPIRED USER_NOT_FOUND OTP_DISABLED
Change Password
POST /api/v1/auth/change-password
Bearer token required Rate limit: 120 / minute

For a signed-in user who knows their current password. Available even when OTP is switched off. Other devices are signed out; the calling token keeps working.

Parameters — JSON body

Parameter Type Required Validation Description
current_password string Required required, must match the stored password Verified against the authenticated account.
Example: Secret@123
password string Required required, min:8, confirmed, different from current_password The new password.
Example: NewSecret@456
password_confirmation string Required required, must equal password Confirmation field.
Example: NewSecret@456

Example request

{
    "current_password": "Secret@123",
    "password": "NewSecret@456",
    "password_confirmation": "NewSecret@456"
}

cURL

curl -X POST 'https://dpbossapp.io/api/v1/auth/change-password' \
  -H 'Accept: application/json' \
  -H 'Content-Type: application/json' \
  -H 'Authorization: Bearer YOUR_TOKEN' \
  -d '{"current_password":"Secret@123","password":"NewSecret@456","password_confirmation":"NewSecret@456"}'

Responses

200 Success
{
    "success": true,
    "message": "Password changed successfully."
}

Possible error codes

VALIDATION_ERROR UNAUTHENTICATED ACCOUNT_INACTIVE

Profile & Devices

Authenticated account management. Send Authorization: Bearer {token} on every call.

Get Profile
GET /api/v1/profile
Bearer token required Rate limit: 120 / minute

Returns the authenticated user. Also the cheapest way to check a stored token is still valid.

Parameters

None.

cURL

curl -X GET 'https://dpbossapp.io/api/v1/profile' \
  -H 'Accept: application/json' \
  -H 'Authorization: Bearer YOUR_TOKEN'

Responses

200 Success
{
    "success": true,
    "message": "Profile fetched successfully.",
    "data": {
        "user": {
            "id": 2,
            "name": "Maharshi Suhagiya",
            "mobile": "9876543210",
            "email": "user@example.com",
            "is_active": true,
            "is_mobile_verified": true,
            "mobile_verified_at": "2026-10-04T12:33:00+00:00",
            "device_type": "android",
            "app_version": "1.0.0",
            "last_login_at": "2026-10-04T13:00:00+00:00",
            "created_at": "2026-10-04T12:33:00+00:00"
        }
    }
}

Possible error codes

UNAUTHENTICATED ACCOUNT_INACTIVE
Update Profile
PUT /api/v1/profile
Bearer token required Rate limit: 120 / minute

Updates name and/or email. Both fields use `sometimes`, so send only what changed. The mobile number cannot be changed here — it is the account identity.

Parameters — JSON body

Parameter Type Required Validation Description
name string Sometimes sometimes required, min:2, max:100, letters / spaces / . ' - only Omit the key to leave the name unchanged.
Example: Maharshi S.
email string Sometimes sometimes, nullable, valid email, max:150, unique:users Send null to clear it. Changing it resets email_verified_at.
Example: new@example.com

Example request

{
    "name": "Maharshi S.",
    "email": "new@example.com"
}

cURL

curl -X PUT 'https://dpbossapp.io/api/v1/profile' \
  -H 'Accept: application/json' \
  -H 'Content-Type: application/json' \
  -H 'Authorization: Bearer YOUR_TOKEN' \
  -d '{"name":"Maharshi S.","email":"new@example.com"}'

Responses

200 Updated
{
    "success": true,
    "message": "Profile updated successfully.",
    "data": {
        "user": {
            "id": 2,
            "name": "Maharshi S.",
            "mobile": "9876543210",
            "email": "new@example.com",
            "is_active": true,
            "is_mobile_verified": true
        }
    }
}

Possible error codes

VALIDATION_ERROR UNAUTHENTICATED ACCOUNT_INACTIVE
Update FCM Token
POST /api/v1/profile/fcm-token
Bearer token required Rate limit: 120 / minute

Call this from Firebase's onNewToken / onTokenRefresh callback. Tokens are keyed by device_id, so one handset keeps one record. If the same token turns up on another account it is detached from the old one, which handles a device changing hands.

Parameters — JSON body

Parameter Type Required Validation Description
fcm_token string Required required, max:500 The fresh registration token.
Example: fZx9K2...A1b
device_type string Optional nullable, in:android,ios,web Platform.
Example: android
device_id string Optional nullable, max:150 Strongly recommended — without it every refresh creates a new device row.
Example: a1b2c3d4e5f6
device_name string Optional nullable, max:100 Device label.
Example: Redmi Note 13
app_version string Optional nullable, max:20 App version.
Example: 1.0.1
notifications_enabled boolean Optional nullable, boolean Set false when the user turns notifications off in-app; the server then skips this device.
Example: true

Example request

{
    "fcm_token": "fZx9K2...A1b",
    "device_type": "android",
    "device_id": "a1b2c3d4e5f6",
    "device_name": "Redmi Note 13",
    "app_version": "1.0.1",
    "notifications_enabled": true
}

cURL

curl -X POST 'https://dpbossapp.io/api/v1/profile/fcm-token' \
  -H 'Accept: application/json' \
  -H 'Content-Type: application/json' \
  -H 'Authorization: Bearer YOUR_TOKEN' \
  -d '{"fcm_token":"fZx9K2...A1b","device_type":"android","device_id":"a1b2c3d4e5f6","device_name":"Redmi Note 13","app_version":"1.0.1","notifications_enabled":true}'

Responses

200 Saved
{
    "success": true,
    "message": "FCM token saved successfully.",
    "data": {
        "device_id": "a1b2c3d4e5f6",
        "notifications_enabled": true
    }
}

Possible error codes

VALIDATION_ERROR UNAUTHENTICATED ACCOUNT_INACTIVE
Delete Account
DELETE /api/v1/profile
Bearer token required Rate limit: 120 / minute

Soft-deletes the account, revokes all tokens and removes every device record. An admin can still see and restore it, and the mobile number stays reserved.

Parameters — JSON body

Parameter Type Required Validation Description
password string Required required, must match the stored password Confirms intent.
Example: Secret@123

Example request

{
    "password": "Secret@123"
}

cURL

curl -X DELETE 'https://dpbossapp.io/api/v1/profile' \
  -H 'Accept: application/json' \
  -H 'Content-Type: application/json' \
  -H 'Authorization: Bearer YOUR_TOKEN' \
  -d '{"password":"Secret@123"}'

Responses

200 Deleted
{
    "success": true,
    "message": "Your account has been deleted."
}

Possible error codes

VALIDATION_ERROR UNAUTHENTICATED ACCOUNT_INACTIVE

Notifications

The in-app inbox. Mirrors what the admin panel pushed, so a missed push is still readable.

List Notifications
GET /api/v1/notifications
Bearer token required Rate limit: 120 / minute

Paginated inbox, newest first.

Parameters — sent as query string

Parameter Type Required Validation Description
page integer Optional nullable, integer, min:1 Page number. Query string.
Example: 1
per_page integer Optional nullable, integer, min:1, max:100 Items per page. Defaults to 20. Query string.
Example: 20
unread_only boolean Optional nullable, boolean Pass 1 to return only unread items. Query string.
Example: 0

Responses

200 Success
{
    "success": true,
    "message": "Notifications fetched successfully.",
    "data": {
        "notifications": [
            {
                "id": 12,
                "title": "Result declared",
                "body": "Today's result is now available in the app.",
                "image_url": null,
                "data": {
                    "screen": "results"
                },
                "is_read": false,
                "read_at": null,
                "created_at": "2026-10-04T13:20:00+00:00"
            }
        ],
        "unread_count": 3,
        "pagination": {
            "current_page": 1,
            "per_page": 20,
            "total": 23,
            "last_page": 2,
            "has_more": true
        }
    }
}

Possible error codes

VALIDATION_ERROR UNAUTHENTICATED ACCOUNT_INACTIVE
Unread Count
GET /api/v1/notifications/unread-count
Bearer token required Rate limit: 120 / minute

Just the badge number — cheap enough to poll.

Parameters

None.

cURL

curl -X GET 'https://dpbossapp.io/api/v1/notifications/unread-count' \
  -H 'Accept: application/json' \
  -H 'Authorization: Bearer YOUR_TOKEN'

Responses

200 Success
{
    "success": true,
    "message": "Unread count fetched successfully.",
    "data": {
        "unread_count": 3
    }
}

Possible error codes

UNAUTHENTICATED ACCOUNT_INACTIVE
Mark One As Read
POST /api/v1/notifications/{id}/read
Bearer token required Rate limit: 120 / minute

Marks a single notification read. 404 if the id belongs to another user.

Parameters — JSON body

Parameter Type Required Validation Description
id path integer Required required, integer, must belong to the authenticated user Path parameter — the notification id.
Example: 12

Responses

200 Success
{
    "success": true,
    "message": "Notification marked as read.",
    "data": {
        "notification": {
            "id": 12,
            "title": "Result declared",
            "is_read": true,
            "read_at": "2026-10-04T13:25:00+00:00"
        }
    }
}

Possible error codes

UNAUTHENTICATED ACCOUNT_INACTIVE NOT_FOUND
Mark All As Read
POST /api/v1/notifications/read-all
Bearer token required Rate limit: 120 / minute

Clears the whole unread badge in one call.

Parameters

None.

cURL

curl -X POST 'https://dpbossapp.io/api/v1/notifications/read-all' \
  -H 'Accept: application/json' \
  -H 'Authorization: Bearer YOUR_TOKEN'

Responses

200 Success
{
    "success": true,
    "message": "All notifications marked as read.",
    "data": {
        "marked_count": 3
    }
}

Possible error codes

UNAUTHENTICATED ACCOUNT_INACTIVE
Delete Notification
DELETE /api/v1/notifications/{id}
Bearer token required Rate limit: 120 / minute

Removes one notification from this user's inbox.

Parameters — JSON body

Parameter Type Required Validation Description
id path integer Required required, integer, must belong to the authenticated user Path parameter — the notification id.
Example: 12

Responses

200 Success
{
    "success": true,
    "message": "Notification deleted successfully."
}

Possible error codes

UNAUTHENTICATED ACCOUNT_INACTIVE NOT_FOUND