BizBook API
REST API for the Book app β auth, labels, events, notes, categories, schedule tasks, note points,
appointments, feedback, settings and content pages.
Every example below is a ready-to-run curl command with the correct base URL for this server.
https://bizbook.nopcypher.com/api
Copy base URL
Auth: JWT Bearer
Content-Type: application/json
Swagger UI β
Quick Start
Three steps from zero to your first authenticated call. Examples are bash β on Windows use Git Bash or import the curl into Postman.
Send an OTP to the mobile number
curl -X POST "https://bizbook.nopcypher.com/api/auth/sendotp" \
-H "Content-Type: application/json" \
-d '{"mobile":"9000000000"}'Login β with password or with the OTP
curl -X POST "https://bizbook.nopcypher.com/api/auth/login" \
-H "Content-Type: application/json" \
-d '{"mobile":"9000000000","password":"Admin@123"}'{
"token": "eyJhbGciOiJIUzI1NiIs...",
"expiresAtUtc": "2026-07-17T10:00:00Z",
"customer": {
"id": 1, "name": "Administrator",
"mobile": "+919000000000", "email": "admin@bizbook.local", "roles": ["Admin"]
}
}Call any endpoint with the token
curl -X GET "https://bizbook.nopcypher.com/api/labels/getall" \ -H "Authorization: Bearer YOUR_TOKEN"
Replace YOUR_TOKEN with the token value from step 2. Tokens are valid for 24 hours.
Conventions
Read once β these rules apply to every module below.
Route pattern
/api/{module}/{action} β actions are getall, getbyid?id=, search?query=, create, update, delete?id=.
One body for create & update
The same JSON shape is used for both. id is ignored on create and required on update (400 without it).
Update sends the full record
Include every field with its current value β not only the one you changed.
Soft delete
Delete flags the record instead of removing it and returns {"success":true,"message":"β¦deleted successfully."}.
Search
Case-insensitive "contains" on the module's Name/Title column; only active (non-deleted) records are returned.
Mobile numbers
Indian only: 10 digits starting 6β9. +91/91/0 prefixes accepted; stored as +91XXXXXXXXXX.
Dates
UTC ISO-8601 in and out: 2026-08-01T10:00:00Z.
Caching
Reads are cached server-side (60 min) and invalidated on every write β responses are always fresh.
Data is per-user
Every record belongs to the logged-in user (from the token). You only ever see and modify your own data β other users' record ids return 404.
Token required β two exceptions
Every endpoint needs Authorization: Bearer except the auth endpoints and content pages, which are public by design.
Authentication
Registration flow: sendotp β verifyotp β register. OTP login flow: sendotp β login (login consumes the OTP β don't call verifyotp in between).
/api/auth/sendotp
Send an OTP to a mobile number
curl -X POST "https://bizbook.nopcypher.com/api/auth/sendotp" \
-H "Content-Type: application/json" \
-d '{"mobile":"9876543210"}'
/api/auth/verifyotp
Verify an OTP (before register)
curl -X POST "https://bizbook.nopcypher.com/api/auth/verifyotp" \
-H "Content-Type: application/json" \
-d '{"mobile":"9876543210","otp":"9876"}'
{ "verified": true, "message": "OTP verified." }
Verification consumes the OTP (single-use).
/api/auth/register
Create an account
curl -X POST "https://bizbook.nopcypher.com/api/auth/register" \
-H "Content-Type: application/json" \
-d '{"name":"Darshil Patel","mobile":"9876543210","email":"darshil@example.com","password":"Secret@123"}'
email is optional (omit it and it stays empty). Returns the same token payload as login. 409 when the mobile number is already registered.
/api/auth/login
Login with password OR otp
curl -X POST "https://bizbook.nopcypher.com/api/auth/login" \
-H "Content-Type: application/json" \
-d '{"mobile":"9876543210","password":"Secret@123"}'
Send password or otp — at least one is required (400 with neither, 401 when wrong). OTP mode: {"mobile":"9876543210","otp":"9876"}.
/api/auth/forgotpassword
Forgot password — step 1, send a reset OTP
curl -X POST "https://bizbook.nopcypher.com/api/auth/forgotpassword" \
-H "Content-Type: application/json" \
-d '{"mobile":"9876543210"}'
{ "message": "If the number is registered, an OTP has been sent." }
Always 200 with this same message, registered or not — the endpoint is anonymous, so confirming which numbers have accounts would leak the customer list. Only a registered number actually receives an OTP.
/api/auth/resetpassword
Forgot password — step 2, set the new password
curl -X POST "https://bizbook.nopcypher.com/api/auth/resetpassword" \
-H "Content-Type: application/json" \
-d '{"mobile":"9876543210","otp":"9876","newPassword":"NewSecret@123"}'
{ "token": "eyJhbGciOi...", "expiresAtUtc": "...", "customer": { ... } }
Do NOT call verify-otp in between — this consumes the OTP itself, so verifying first spends it and this call then fails. newPassword must be at least 6 characters. Returns a token so the app can go straight to the signed-in state. Wrong or spent OTP returns 401.
/api/auth/getprofile
Current user's profile from the token
curl -X GET "https://bizbook.nopcypher.com/api/auth/getprofile" \ -H "Authorization: Bearer YOUR_TOKEN"
{ "id": 1, "name": "Administrator", "mobile": "+919000000000", "email": "admin@bizbook.local", "roles": ["Admin"] }
🏷️ Labels
/api/labels/getall
List all active records
curl -X GET "https://bizbook.nopcypher.com/api/labels/getall" \ -H "Authorization: Bearer YOUR_TOKEN"
/api/labels/getbyid
Single record by id (404 if missing/deleted)
curl -X GET "https://bizbook.nopcypher.com/api/labels/getbyid?id=1" \ -H "Authorization: Bearer YOUR_TOKEN"
/api/labels/search
Search by name/title (contains, case-insensitive)
curl -X GET "https://bizbook.nopcypher.com/api/labels/search?query=trip" \ -H "Authorization: Bearer YOUR_TOKEN"
/api/labels/create
Create — id in the body is ignored
curl -X POST "https://bizbook.nopcypher.com/api/labels/create" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"name":"Personal","displayOrder":1,"isBookmarked":false}'
Returns 201 with the created record including its new id.
/api/labels/update
Update — id required in the body
curl -X PUT "https://bizbook.nopcypher.com/api/labels/update" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"id":1,"name":"Personal Updated","displayOrder":1,"isBookmarked":true}'
Returns 200 with the updated record (updatedOnUtc stamped). 400 when id is missing, 404 when it doesn't exist.
/api/labels/delete
Soft delete
curl -X DELETE "https://bizbook.nopcypher.com/api/labels/delete?id=1" \ -H "Authorization: Bearer YOUR_TOKEN"
{ "success": true, "message": "Label deleted successfully." }
📍 Events
/api/events/getall
List all active records
curl -X GET "https://bizbook.nopcypher.com/api/events/getall" \ -H "Authorization: Bearer YOUR_TOKEN"
/api/events/getbyid
Single record by id (404 if missing/deleted)
curl -X GET "https://bizbook.nopcypher.com/api/events/getbyid?id=1" \ -H "Authorization: Bearer YOUR_TOKEN"
/api/events/search
Search by name/title (contains, case-insensitive)
curl -X GET "https://bizbook.nopcypher.com/api/events/search?query=trip" \ -H "Authorization: Bearer YOUR_TOKEN"
/api/events/create
Create — id in the body is ignored
curl -X POST "https://bizbook.nopcypher.com/api/events/create" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"name":"Goa Trip","country":"India","state":"Goa","city":"Panaji","address":"Beach Road, Panaji","latitude":15.49681,"longitude":73.82754,"enableIcon":true,"iconName":"Flag","displayOrder":1,"isBookmarked":false}'
Returns 201 with the created record including its new id.
/api/events/update
Update — id required in the body
curl -X PUT "https://bizbook.nopcypher.com/api/events/update" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"id":1,"name":"Goa Trip 2026","country":"India","state":"Goa","city":"Panaji","enableIcon":false,"displayOrder":1,"isBookmarked":true}'
Returns 200 with the updated record (updatedOnUtc stamped). 400 when id is missing, 404 when it doesn't exist.
/api/events/delete
Soft delete
curl -X DELETE "https://bizbook.nopcypher.com/api/events/delete?id=1" \ -H "Authorization: Bearer YOUR_TOKEN"
{ "success": true, "message": "Event deleted successfully." }
/api/events/geticons
The icon choices for events
curl -X GET "https://bizbook.nopcypher.com/api/events/geticons" \ -H "Authorization: Bearer YOUR_TOKEN"
[ { "name": "Default", "path": "" }, { "name": "Home", "path": "" }, { "name": "Favorite", "path": "" },
{ "name": "Profile", "path": "" }, { "name": "Settings", "path": "" }, { "name": "Flag", "path": "" } ]
📝 Notes
/api/notes/getall
List all active records
curl -X GET "https://bizbook.nopcypher.com/api/notes/getall" \ -H "Authorization: Bearer YOUR_TOKEN"
/api/notes/getbyid
Single record by id (404 if missing/deleted)
curl -X GET "https://bizbook.nopcypher.com/api/notes/getbyid?id=1" \ -H "Authorization: Bearer YOUR_TOKEN"
/api/notes/search
Search by name/title (contains, case-insensitive)
curl -X GET "https://bizbook.nopcypher.com/api/notes/search?query=trip" \ -H "Authorization: Bearer YOUR_TOKEN"
/api/notes/create
Create — id in the body is ignored
curl -X POST "https://bizbook.nopcypher.com/api/notes/create" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"name":"Buy groceries","labelId":1,"isQuickNote":false,"eventId":1,"displayOrder":1,"isBookmarked":false}'
Returns 201 with the created record including its new id.
/api/notes/update
Update — id required in the body
curl -X PUT "https://bizbook.nopcypher.com/api/notes/update" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"id":1,"name":"Buy groceries + snacks","labelId":2,"isQuickNote":false,"eventId":1,"displayOrder":1,"isBookmarked":false}'
Returns 200 with the updated record (updatedOnUtc stamped). 400 when id is missing, 404 when it doesn't exist.
/api/notes/delete
Soft delete
curl -X DELETE "https://bizbook.nopcypher.com/api/notes/delete?id=1" \ -H "Authorization: Bearer YOUR_TOKEN"
{ "success": true, "message": "Note deleted successfully." }
/api/notes/getall?isQuickNote=true
Quick notes only (false = regular only)
curl -X GET "https://bizbook.nopcypher.com/api/notes/getall?isQuickNote=true" \ -H "Authorization: Bearer YOUR_TOKEN"
📂 Categories
/api/categories/getall
List all active records
curl -X GET "https://bizbook.nopcypher.com/api/categories/getall" \ -H "Authorization: Bearer YOUR_TOKEN"
/api/categories/getbyid
Single record by id (404 if missing/deleted)
curl -X GET "https://bizbook.nopcypher.com/api/categories/getbyid?id=1" \ -H "Authorization: Bearer YOUR_TOKEN"
/api/categories/search
Search by name/title (contains, case-insensitive)
curl -X GET "https://bizbook.nopcypher.com/api/categories/search?query=trip" \ -H "Authorization: Bearer YOUR_TOKEN"
/api/categories/create
Create — id in the body is ignored
curl -X POST "https://bizbook.nopcypher.com/api/categories/create" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"title":"Work","displayOrder":1,"isBookmarked":false}'
Returns 201 with the created record including its new id.
/api/categories/update
Update — id required in the body
curl -X PUT "https://bizbook.nopcypher.com/api/categories/update" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"id":1,"title":"Work Items","displayOrder":1,"isBookmarked":true}'
Returns 200 with the updated record (updatedOnUtc stamped). 400 when id is missing, 404 when it doesn't exist.
/api/categories/delete
Soft delete
curl -X DELETE "https://bizbook.nopcypher.com/api/categories/delete?id=1" \ -H "Authorization: Bearer YOUR_TOKEN"
{ "success": true, "message": "Categorie deleted successfully." }
✅ Schedule Tasks
/api/scheduletasks/getall
List all active records
curl -X GET "https://bizbook.nopcypher.com/api/scheduletasks/getall" \ -H "Authorization: Bearer YOUR_TOKEN"
/api/scheduletasks/getbyid
Single record by id (404 if missing/deleted)
curl -X GET "https://bizbook.nopcypher.com/api/scheduletasks/getbyid?id=1" \ -H "Authorization: Bearer YOUR_TOKEN"
/api/scheduletasks/search
Search by name/title (contains, case-insensitive)
curl -X GET "https://bizbook.nopcypher.com/api/scheduletasks/search?query=trip" \ -H "Authorization: Bearer YOUR_TOKEN"
/api/scheduletasks/create
Create — id in the body is ignored
curl -X POST "https://bizbook.nopcypher.com/api/scheduletasks/create" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"title":"Call the venue","scheduleDateOnUtc":"2026-08-01T10:00:00Z","categoryId":1,"displayOrder":1,"isBookmarked":false}'
Returns 201 with the created record including its new id.
/api/scheduletasks/update
Update — id required in the body
curl -X PUT "https://bizbook.nopcypher.com/api/scheduletasks/update" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"id":1,"title":"Call the venue (done)","scheduleDateOnUtc":"2026-08-02T10:00:00Z","categoryId":1,"displayOrder":1,"isBookmarked":true}'
Returns 200 with the updated record (updatedOnUtc stamped). 400 when id is missing, 404 when it doesn't exist.
/api/scheduletasks/delete
Soft delete
curl -X DELETE "https://bizbook.nopcypher.com/api/scheduletasks/delete?id=1" \ -H "Authorization: Bearer YOUR_TOKEN"
{ "success": true, "message": "Schedule Task deleted successfully." }
/api/scheduletasks/search?date=
Calendar view — tasks scheduled on a day
curl -X GET "https://bizbook.nopcypher.com/api/scheduletasks/search?date=2026-08-01" \ -H "Authorization: Bearer YOUR_TOKEN"
date is the UTC day of scheduleDateOnUtc. Combine with text: ?query=call&date=2026-08-01. At least one of query/date is required.
🧩 Note Points
/api/notepoints/getall
List all active records
curl -X GET "https://bizbook.nopcypher.com/api/notepoints/getall" \ -H "Authorization: Bearer YOUR_TOKEN"
/api/notepoints/getbyid
Single record by id (404 if missing/deleted)
curl -X GET "https://bizbook.nopcypher.com/api/notepoints/getbyid?id=1" \ -H "Authorization: Bearer YOUR_TOKEN"
/api/notepoints/search
Search by name/title (contains, case-insensitive)
curl -X GET "https://bizbook.nopcypher.com/api/notepoints/search?query=trip" \ -H "Authorization: Bearer YOUR_TOKEN"
/api/notepoints/create
Create (multipart/form-data, files optional)
curl -X POST "https://bizbook.nopcypher.com/api/notepoints/create" \ -H "Authorization: Bearer YOUR_TOKEN" \ -F "noteId=1" \ -F "pointType=Audio" \ -F "title=Voice memo" \ -F "audioRecordingDuration=42" \ -F "audioRecordingFile=@/path/to/recording.m4a"
noteId is required (the note this point belongs to). Also: imageFile=@photo.jpg, drawingFile=@sketch.png. Returns 201 with the server-generated file names (audioRecordingFileName, imageFileName, drawingFileName).
/api/notepoints/update
Update (multipart/form-data) — id required
curl -X PUT "https://bizbook.nopcypher.com/api/notepoints/update" \ -H "Authorization: Bearer YOUR_TOKEN" \ -F "id=1" \ -F "noteId=1" \ -F "pointType=Audio" \ -F "title=Voice memo v2" \ -F "audioRecordingFile=@/path/to/new-recording.m4a"
A newly sent file replaces the stored one (the old file is deleted from disk). Omit the file fields to keep existing files. 400 when id is missing, 404 when it doesn't exist.
/api/notepoints/delete
Soft delete
curl -X DELETE "https://bizbook.nopcypher.com/api/notepoints/delete?id=1" \ -H "Authorization: Bearer YOUR_TOKEN"
{ "success": true, "message": "Note Point deleted successfully." }
/api/notepoints/getpointtypes
The 8 valid pointType values
curl -X GET "https://bizbook.nopcypher.com/api/notepoints/getpointtypes" \ -H "Authorization: Bearer YOUR_TOKEN"
[ "Text", "Location", "Audio", "Image", "Checklist", "Appointment", "Contact", "Drawing" ]
/api/notepoints/getfile
Download/stream a stored file
curl -X GET "https://bizbook.nopcypher.com/api/notepoints/getfile?id=1&fileType=image" \ -H "Authorization: Bearer YOUR_TOKEN" \ --output photo.jpg
fileType: audiorecording | image | drawing. Streams with the right content type (audio supports range requests for seeking). 404 when the note point has no such file or belongs to another user.
📅 Appointments
/api/appointments/getall
List all active records
curl -X GET "https://bizbook.nopcypher.com/api/appointments/getall" \ -H "Authorization: Bearer YOUR_TOKEN"
/api/appointments/getbyid
Single record by id (404 if missing/deleted)
curl -X GET "https://bizbook.nopcypher.com/api/appointments/getbyid?id=1" \ -H "Authorization: Bearer YOUR_TOKEN"
/api/appointments/search
Search by name/title (contains, case-insensitive)
curl -X GET "https://bizbook.nopcypher.com/api/appointments/search?query=trip" \ -H "Authorization: Bearer YOUR_TOKEN"
/api/appointments/create
Create — id in the body is ignored
curl -X POST "https://bizbook.nopcypher.com/api/appointments/create" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"title":"Dentist visit","description":"Annual checkup","fromDateOnUtc":"2026-08-01T09:00:00Z","toDateOnUtc":"2026-08-01T09:30:00Z","isNotificationOn":true,"displayOrder":1,"isBookmarked":false}'
Returns 201 with the created record including its new id.
/api/appointments/update
Update — id required in the body
curl -X PUT "https://bizbook.nopcypher.com/api/appointments/update" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"id":1,"title":"Dentist visit (rescheduled)","fromDateOnUtc":"2026-08-02T09:00:00Z","toDateOnUtc":"2026-08-02T09:30:00Z","isNotificationOn":false,"displayOrder":1,"isBookmarked":false}'
Returns 200 with the updated record (updatedOnUtc stamped). 400 when id is missing, 404 when it doesn't exist.
/api/appointments/delete
Soft delete
curl -X DELETE "https://bizbook.nopcypher.com/api/appointments/delete?id=1" \ -H "Authorization: Bearer YOUR_TOKEN"
{ "success": true, "message": "Appointment deleted successfully." }
/api/appointments/search?date=
Calendar view — appointments touching a day
curl -X GET "https://bizbook.nopcypher.com/api/appointments/search?date=2026-08-01" \ -H "Authorization: Bearer YOUR_TOKEN"
Matches any appointment whose From–To range touches that UTC day (multi-day appointments match every day they span). Combine with text: ?query=dentist&date=2026-08-01.
💬 Feedback
/api/feedbacks/getall
List all active records
curl -X GET "https://bizbook.nopcypher.com/api/feedbacks/getall" \ -H "Authorization: Bearer YOUR_TOKEN"
/api/feedbacks/getbyid
Single record by id (404 if missing/deleted)
curl -X GET "https://bizbook.nopcypher.com/api/feedbacks/getbyid?id=1" \ -H "Authorization: Bearer YOUR_TOKEN"
/api/feedbacks/search
Search by name/title (contains, case-insensitive)
curl -X GET "https://bizbook.nopcypher.com/api/feedbacks/search?query=trip" \ -H "Authorization: Bearer YOUR_TOKEN"
/api/feedbacks/create
Create — id in the body is ignored
curl -X POST "https://bizbook.nopcypher.com/api/feedbacks/create" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"message":"Loving the app — please add a dark mode for the notes screen.","displayOrder":1,"isBookmarked":false}'
Returns 201 with the created record including its new id.
/api/feedbacks/update
Update — id required in the body
curl -X PUT "https://bizbook.nopcypher.com/api/feedbacks/update" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"id":1,"message":"Loving the app — dark mode request (updated).","displayOrder":1,"isBookmarked":true}'
Returns 200 with the updated record (updatedOnUtc stamped). 400 when id is missing, 404 when it doesn't exist.
/api/feedbacks/delete
Soft delete
curl -X DELETE "https://bizbook.nopcypher.com/api/feedbacks/delete?id=1" \ -H "Authorization: Bearer YOUR_TOKEN"
{ "success": true, "message": "Feedback deleted successfully." }
βοΈ Settings
id: 0./api/settings/getsetting
The current user's app settings
curl -X GET "https://bizbook.nopcypher.com/api/settings/getsetting" \ -H "Authorization: Bearer YOUR_TOKEN"
{ "customerId": 5, "themeName": "Dark", "languageName": "English", "notificationName": "All", "isLock": false, "id": 1 }
/api/settings/save
Save settings (create on first save, update afterwards)
curl -X POST "https://bizbook.nopcypher.com/api/settings/save" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"themeName":"Dark","languageName":"English","notificationName":"All","isLock":false}'
All fields optional; isLock defaults to false. Returns the saved record.
π³ Membership Plans
/api/plans/getall
Active plans in display order
curl -X GET "https://bizbook.nopcypher.com/api/plans/getall"
[
{ "id": 1, "name": "Free", "description": "Everything you need to get organised.",
"price": 0.00, "currency": "INR", "billingPeriod": "forever", "priceOnRequest": false,
"features": ["Events and places", "Notes with labels"],
"isFree": true, "isDefault": true, "isPopular": false, "displayOrder": 10 },
{ "id": 2, "name": "Professional", "price": 0.00, "priceOnRequest": true,
"features": ["Unlimited events", "Priority support"],
"isFree": false, "isDefault": false, "isPopular": true, "displayOrder": 20 }
]
features arrives as a ready-made array — no splitting needed on the client.
/api/plans/getbyid
One active plan by id
curl -X GET "https://bizbook.nopcypher.com/api/plans/getbyid?id=1"
404 when the id is unknown or the plan has been deactivated in the admin panel.
priceOnRequest is true show
Custom and a Contact us action β the price has not been set yet. When
isFree is true show Free rather than "βΉ0". Otherwise show
currency + price, followed by billingPeriod.
isPopular marks the card to highlight and isDefault is the plan a
customer receives if they register without choosing.
Payments are not live yet, so every paid plan should lead to Contact us
for now.
π« My Membership
getcurrent right after login β when hasPlan
is false the customer has never chosen a plan, so show the picker
(fill it from api/plans/getall) and post their choice to
selectplan. Browsing plans is anonymous; everything here needs the token.
/api/membership/getcurrent
The customer's current plan
curl -X GET "https://bizbook.nopcypher.com/api/membership/getcurrent" \ -H "Authorization: Bearer YOUR_TOKEN"
{ "hasPlan": true, "membershipId": 12,
"plan": { "id": 1, "name": "Free", "features": [ ... ], "isFree": true },
"startsOnUtc": "2026-07-22T10:20:11", "endsOnUtc": null, "source": "Registration" }
hasPlan false means no plan has ever been chosen — plan is null and the app should prompt. endsOnUtc is null while the membership is open-ended; it exists for paid periods later.
/api/membership/selectplan
Choose or change plan
curl -X POST "https://bizbook.nopcypher.com/api/membership/selectplan" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"planId":2}'
(the same shape as getcurrent, reflecting the new plan)
Closes the current membership and opens a new one, so the change lands in the history. Selecting the plan already held changes nothing and adds no row. 404 for an unknown plan, 400 for a deactivated one or a missing planId.
/api/membership/gethistory
Every plan the customer has held
curl -X GET "https://bizbook.nopcypher.com/api/membership/gethistory" \ -H "Authorization: Bearer YOUR_TOKEN"
[
{ "id": 3, "planId": 4, "planName": "Business", "startsOnUtc": "...", "endsOnUtc": null, "isCurrent": true, "source": "SelfSelected" },
{ "id": 2, "planId": 2, "planName": "Professional", "endsOnUtc": "...", "isCurrent": false, "source": "SelfSelected" },
{ "id": 1, "planId": 1, "planName": "Free", "endsOnUtc": "...", "isCurrent": false, "source": "Registration" }
]
Newest first. source is Registration, SelfSelected, Admin or Backfill.
POST /api/auth/register now takes an optional
planId. Send the customer's choice and they start on that plan; omit it and
they get the default free plan, so older app builds keep working unchanged.
Payments don't exist yet β selecting a paid plan simply records it, nothing
is charged.
π Countries & States
getall to fill the country picker, then getstates once the
user picks one. Events store these as plain text in their country and
state fields.
/api/countries/getall
Every country, alphabetical by name
curl -X GET "https://bizbook.nopcypher.com/api/countries/getall" \ -H "Authorization: Bearer YOUR_TOKEN"
[
{ "code": "AR", "name": "Argentina", "stateCount": 24 },
{ "code": "IN", "name": "India", "stateCount": 36 }
]
stateCount lets the app skip the state picker for a country that has no states listed.
/api/countries/getstates
States of one country
curl -X GET "https://bizbook.nopcypher.com/api/countries/getstates?country=IN" \ -H "Authorization: Bearer YOUR_TOKEN"
[
{ "name": "Gujarat", "code": "GJ" },
{ "name": "Maharashtra", "code": "MH" }
]
country is the ISO code from getall and is case-insensitive. 404 for an unknown code, 400 when it is missing.
code is always the ISO-3166
two-letter code and is safe to store. For states it is different β only about half the
rows in the source data have a real abbreviation, so code falls back to the
full state name (every UK county, for instance). Abbreviations are also not unique
in a few countries: Vietnam has three states coded QN and Romania codes all six
BucureΘti sectors as B. State names are unique within a country,
so storing the name is the safer choice if you want to map the value back to a state later.
π Content Pages
/api/pages/getall
All published pages (no body)
curl -X GET "https://bizbook.nopcypher.com/api/pages/getall"
[
{ "id": 1, "slug": "privacy-policy", "title": "Privacy Policy", "body": null,
"metaDescription": "How BizBook collects...", "displayOrder": 10, "updatedOnUtc": "2026-07-21T08:48:12" },
{ "id": 2, "slug": "terms-and-conditions", "title": "Terms and Conditions", "body": null, ... }
]
body is deliberately null here so building a menu doesn't download every page. Fetch the content with getbyslug when the user opens a page.
/api/pages/getbyslug
One page with its full HTML body
curl -X GET "https://bizbook.nopcypher.com/api/pages/getbyslug?slug=privacy-policy"
{ "id": 1, "slug": "privacy-policy", "title": "Privacy Policy",
"body": "<p>...</p><h2>Information we collect</h2>...",
"metaDescription": "...", "displayOrder": 10, "updatedOnUtc": "2026-07-21T08:48:12" }
Prefer slug over id — slugs are stable and readable, ids change if a page is ever recreated. 404 when the slug is unknown or the page is unpublished; 400 when slug is missing.
/api/pages/getbyid
Same as getbyslug, by numeric id
curl -X GET "https://bizbook.nopcypher.com/api/pages/getbyid?id=1"
body is HTML, so render it with an HTML-capable widget
(flutter_html or a WebView) β not a plain Text widget. Cache pages locally and use
updatedOnUtc from getall to decide when to refetch. The four slugs
privacy-policy, terms-and-conditions, help-and-support and
contact-us always exist and are safe to hard-code.
Error Reference
All errors are JSON. The shapes below are consistent across every endpoint.
| Status | When | Body |
|---|---|---|
| 400 | Validation failed β bad field value, missing id on update, invalid OTP/mobile, bad reference id | {"message":"..."} |
| 401 | No token sent | {"success":false,"message":"Authorization is required."} |
| 401 | Invalid / expired token, wrong credentials | {"success":false,"message":"Invalid or expired session. Login again."} |
| 404 | Record not found or already deleted | {"message":"... not found."} |
| 409 | Duplicate β label name or mobile number | {"message":"... already exists."} |