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.

Base URL  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.

1
Send an OTP to the mobile number
bash
curl -X POST "https://bizbook.nopcypher.com/api/auth/sendotp" \
  -H "Content-Type: application/json" \
  -d '{"mobile":"9000000000"}'
Development note: no SMS is sent yet β€” the OTP is the first 4 digits of the mobile number (9000000000 β†’ 9000). It expires in 10 minutes and is single-use.
2
Login β€” with password or with the OTP
bash
curl -X POST "https://bizbook.nopcypher.com/api/auth/login" \
  -H "Content-Type: application/json" \
  -d '{"mobile":"9000000000","password":"Admin@123"}'
response Β· 200
{
  "token": "eyJhbGciOiJIUzI1NiIs...",
  "expiresAtUtc": "2026-07-17T10:00:00Z",
  "customer": {
    "id": 1, "name": "Administrator",
    "mobile": "+919000000000", "email": "admin@bizbook.local", "roles": ["Admin"]
  }
}
3
Call any endpoint with the token
bash
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).

POST /api/auth/sendotp Send an OTP to a mobile number
bash
curl -X POST "https://bizbook.nopcypher.com/api/auth/sendotp" \
  -H "Content-Type: application/json" \
  -d '{"mobile":"9876543210"}'
POST /api/auth/verifyotp Verify an OTP (before register)
bash
curl -X POST "https://bizbook.nopcypher.com/api/auth/verifyotp" \
  -H "Content-Type: application/json" \
  -d '{"mobile":"9876543210","otp":"9876"}'
response
{ "verified": true, "message": "OTP verified." }

Verification consumes the OTP (single-use).

POST /api/auth/register Create an account
bash
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.

POST /api/auth/login Login with password OR otp
bash
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"}.

POST /api/auth/forgotpassword Forgot password — step 1, send a reset OTP
bash
curl -X POST "https://bizbook.nopcypher.com/api/auth/forgotpassword" \
  -H "Content-Type: application/json" \
  -d '{"mobile":"9876543210"}'
response
{ "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.

POST /api/auth/resetpassword Forgot password — step 2, set the new password
bash
curl -X POST "https://bizbook.nopcypher.com/api/auth/resetpassword" \
  -H "Content-Type: application/json" \
  -d '{"mobile":"9876543210","otp":"9876","newPassword":"NewSecret@123"}'
response
{ "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.

GET /api/auth/getprofile Current user's profile from the token
bash
curl -X GET "https://bizbook.nopcypher.com/api/auth/getprofile" \
  -H "Authorization: Bearer YOUR_TOKEN"
response
{ "id": 1, "name": "Administrator", "mobile": "+919000000000", "email": "admin@bizbook.local", "roles": ["Admin"] }

🏷️ Labels

Label names must be unique per user — a duplicate name returns 409. Every new account starts with two labels: Normal and Important.
GET /api/labels/getall List all active records
bash
curl -X GET "https://bizbook.nopcypher.com/api/labels/getall" \
  -H "Authorization: Bearer YOUR_TOKEN"
GET /api/labels/getbyid Single record by id (404 if missing/deleted)
bash
curl -X GET "https://bizbook.nopcypher.com/api/labels/getbyid?id=1" \
  -H "Authorization: Bearer YOUR_TOKEN"
GET /api/labels/search Search by name/title (contains, case-insensitive)
bash
curl -X GET "https://bizbook.nopcypher.com/api/labels/search?query=trip" \
  -H "Authorization: Bearer YOUR_TOKEN"
POST /api/labels/create Create — id in the body is ignored
bash
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.

PUT /api/labels/update Update — id required in the body
bash
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.

DELETE /api/labels/delete Soft delete
bash
curl -X DELETE "https://bizbook.nopcypher.com/api/labels/delete?id=1" \
  -H "Authorization: Bearer YOUR_TOKEN"
response
{ "success": true, "message": "Label deleted successfully." }

📍 Events

iconName must be one of the values from geticons and is required when enableIcon is true. Latitude −90…90, longitude −180…180. country / state / city are free text (max 100 characters each) — the app sends names, there are no lookup ids.
GET /api/events/getall List all active records
bash
curl -X GET "https://bizbook.nopcypher.com/api/events/getall" \
  -H "Authorization: Bearer YOUR_TOKEN"
GET /api/events/getbyid Single record by id (404 if missing/deleted)
bash
curl -X GET "https://bizbook.nopcypher.com/api/events/getbyid?id=1" \
  -H "Authorization: Bearer YOUR_TOKEN"
GET /api/events/search Search by name/title (contains, case-insensitive)
bash
curl -X GET "https://bizbook.nopcypher.com/api/events/search?query=trip" \
  -H "Authorization: Bearer YOUR_TOKEN"
POST /api/events/create Create — id in the body is ignored
bash
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.

PUT /api/events/update Update — id required in the body
bash
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.

DELETE /api/events/delete Soft delete
bash
curl -X DELETE "https://bizbook.nopcypher.com/api/events/delete?id=1" \
  -H "Authorization: Bearer YOUR_TOKEN"
response
{ "success": true, "message": "Event deleted successfully." }
GET /api/events/geticons The icon choices for events
bash
curl -X GET "https://bizbook.nopcypher.com/api/events/geticons" \
  -H "Authorization: Bearer YOUR_TOKEN"
response
[ { "name": "Default", "path": "" }, { "name": "Home", "path": "" }, { "name": "Favorite", "path": "" },
  { "name": "Profile", "path": "" }, { "name": "Settings", "path": "" }, { "name": "Flag", "path": "" } ]

📝 Notes

A normal note (isQuickNote=false) lives under an event — eventId is required and must reference your own event. Quick notes (isQuickNote=true) need no eventId (stored as 0). labelId is optional but must reference an existing label when sent. getall supports ?isQuickNote=true|false and ?eventId= to list one event's notes.
GET /api/notes/getall List all active records
bash
curl -X GET "https://bizbook.nopcypher.com/api/notes/getall" \
  -H "Authorization: Bearer YOUR_TOKEN"
GET /api/notes/getbyid Single record by id (404 if missing/deleted)
bash
curl -X GET "https://bizbook.nopcypher.com/api/notes/getbyid?id=1" \
  -H "Authorization: Bearer YOUR_TOKEN"
GET /api/notes/search Search by name/title (contains, case-insensitive)
bash
curl -X GET "https://bizbook.nopcypher.com/api/notes/search?query=trip" \
  -H "Authorization: Bearer YOUR_TOKEN"
POST /api/notes/create Create — id in the body is ignored
bash
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.

PUT /api/notes/update Update — id required in the body
bash
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.

DELETE /api/notes/delete Soft delete
bash
curl -X DELETE "https://bizbook.nopcypher.com/api/notes/delete?id=1" \
  -H "Authorization: Bearer YOUR_TOKEN"
response
{ "success": true, "message": "Note deleted successfully." }
GET /api/notes/getall?isQuickNote=true Quick notes only (false = regular only)
bash
curl -X GET "https://bizbook.nopcypher.com/api/notes/getall?isQuickNote=true" \
  -H "Authorization: Bearer YOUR_TOKEN"

📂 Categories

title is required. Categories are referenced by schedule tasks.
GET /api/categories/getall List all active records
bash
curl -X GET "https://bizbook.nopcypher.com/api/categories/getall" \
  -H "Authorization: Bearer YOUR_TOKEN"
GET /api/categories/getbyid Single record by id (404 if missing/deleted)
bash
curl -X GET "https://bizbook.nopcypher.com/api/categories/getbyid?id=1" \
  -H "Authorization: Bearer YOUR_TOKEN"
GET /api/categories/search Search by name/title (contains, case-insensitive)
bash
curl -X GET "https://bizbook.nopcypher.com/api/categories/search?query=trip" \
  -H "Authorization: Bearer YOUR_TOKEN"
POST /api/categories/create Create — id in the body is ignored
bash
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.

PUT /api/categories/update Update — id required in the body
bash
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.

DELETE /api/categories/delete Soft delete
bash
curl -X DELETE "https://bizbook.nopcypher.com/api/categories/delete?id=1" \
  -H "Authorization: Bearer YOUR_TOKEN"
response
{ "success": true, "message": "Categorie deleted successfully." }

✅ Schedule Tasks

categoryId is optional but must reference an existing category when sent. Dates are UTC ISO-8601.
GET /api/scheduletasks/getall List all active records
bash
curl -X GET "https://bizbook.nopcypher.com/api/scheduletasks/getall" \
  -H "Authorization: Bearer YOUR_TOKEN"
GET /api/scheduletasks/getbyid Single record by id (404 if missing/deleted)
bash
curl -X GET "https://bizbook.nopcypher.com/api/scheduletasks/getbyid?id=1" \
  -H "Authorization: Bearer YOUR_TOKEN"
GET /api/scheduletasks/search Search by name/title (contains, case-insensitive)
bash
curl -X GET "https://bizbook.nopcypher.com/api/scheduletasks/search?query=trip" \
  -H "Authorization: Bearer YOUR_TOKEN"
POST /api/scheduletasks/create Create — id in the body is ignored
bash
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.

PUT /api/scheduletasks/update Update — id required in the body
bash
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.

DELETE /api/scheduletasks/delete Soft delete
bash
curl -X DELETE "https://bizbook.nopcypher.com/api/scheduletasks/delete?id=1" \
  -H "Authorization: Bearer YOUR_TOKEN"
response
{ "success": true, "message": "Schedule Task deleted successfully." }
GET /api/scheduletasks/search?date= Calendar view — tasks scheduled on a day
bash
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

A note point is one content block inside a note — noteId is always required and must reference your own note (getall supports ?noteId= to list one note's points). pointType must be one of the 8 values from getpointtypes — send only the field group matching the type. For Appointment points: create the appointment via api/appointments first, then send its id as appointmentId (validated as yours). Create/update are multipart/form-data: files go in audioRecordingFile / imageFile / drawingFile; the server generates the stored file name and returns it — sending a new file on update replaces and deletes the old one, omitting it keeps the existing file. checklistJson must be a JSON array as a string. contactPhone / contactEmail accept multiple values separated by ||. audioRecordingDuration is in seconds.
GET /api/notepoints/getall List all active records
bash
curl -X GET "https://bizbook.nopcypher.com/api/notepoints/getall" \
  -H "Authorization: Bearer YOUR_TOKEN"
GET /api/notepoints/getbyid Single record by id (404 if missing/deleted)
bash
curl -X GET "https://bizbook.nopcypher.com/api/notepoints/getbyid?id=1" \
  -H "Authorization: Bearer YOUR_TOKEN"
GET /api/notepoints/search Search by name/title (contains, case-insensitive)
bash
curl -X GET "https://bizbook.nopcypher.com/api/notepoints/search?query=trip" \
  -H "Authorization: Bearer YOUR_TOKEN"
POST /api/notepoints/create Create (multipart/form-data, files optional)
bash
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).

PUT /api/notepoints/update Update (multipart/form-data) — id required
bash
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.

DELETE /api/notepoints/delete Soft delete
bash
curl -X DELETE "https://bizbook.nopcypher.com/api/notepoints/delete?id=1" \
  -H "Authorization: Bearer YOUR_TOKEN"
response
{ "success": true, "message": "Note Point deleted successfully." }
GET /api/notepoints/getpointtypes The 8 valid pointType values
bash
curl -X GET "https://bizbook.nopcypher.com/api/notepoints/getpointtypes" \
  -H "Authorization: Bearer YOUR_TOKEN"
response
[ "Text", "Location", "Audio", "Image", "Checklist", "Appointment", "Contact", "Drawing" ]
GET /api/notepoints/getfile Download/stream a stored file
bash
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

toDateOnUtc can't be earlier than fromDateOnUtc. All fields are optional.
GET /api/appointments/getall List all active records
bash
curl -X GET "https://bizbook.nopcypher.com/api/appointments/getall" \
  -H "Authorization: Bearer YOUR_TOKEN"
GET /api/appointments/getbyid Single record by id (404 if missing/deleted)
bash
curl -X GET "https://bizbook.nopcypher.com/api/appointments/getbyid?id=1" \
  -H "Authorization: Bearer YOUR_TOKEN"
GET /api/appointments/search Search by name/title (contains, case-insensitive)
bash
curl -X GET "https://bizbook.nopcypher.com/api/appointments/search?query=trip" \
  -H "Authorization: Bearer YOUR_TOKEN"
POST /api/appointments/create Create — id in the body is ignored
bash
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.

PUT /api/appointments/update Update — id required in the body
bash
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.

DELETE /api/appointments/delete Soft delete
bash
curl -X DELETE "https://bizbook.nopcypher.com/api/appointments/delete?id=1" \
  -H "Authorization: Bearer YOUR_TOKEN"
response
{ "success": true, "message": "Appointment deleted successfully." }
GET /api/appointments/search?date= Calendar view — appointments touching a day
bash
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

User feedback messages. All fields are optional; search matches on the message text.
GET /api/feedbacks/getall List all active records
bash
curl -X GET "https://bizbook.nopcypher.com/api/feedbacks/getall" \
  -H "Authorization: Bearer YOUR_TOKEN"
GET /api/feedbacks/getbyid Single record by id (404 if missing/deleted)
bash
curl -X GET "https://bizbook.nopcypher.com/api/feedbacks/getbyid?id=1" \
  -H "Authorization: Bearer YOUR_TOKEN"
GET /api/feedbacks/search Search by name/title (contains, case-insensitive)
bash
curl -X GET "https://bizbook.nopcypher.com/api/feedbacks/search?query=trip" \
  -H "Authorization: Bearer YOUR_TOKEN"
POST /api/feedbacks/create Create — id in the body is ignored
bash
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.

PUT /api/feedbacks/update Update — id required in the body
bash
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.

DELETE /api/feedbacks/delete Soft delete
bash
curl -X DELETE "https://bizbook.nopcypher.com/api/feedbacks/delete?id=1" \
  -H "Authorization: Bearer YOUR_TOKEN"
response
{ "success": true, "message": "Feedback deleted successfully." }

βš™οΈ Settings

The mobile app's settings β€” exactly one record per user (no list, no delete). Save is an upsert: the first save creates the record, later saves update it. Get always returns 200 β€” an unsaved user receives defaults with id: 0.
GET /api/settings/getsetting The current user's app settings
bash
curl -X GET "https://bizbook.nopcypher.com/api/settings/getsetting" \
  -H "Authorization: Bearer YOUR_TOKEN"
response
{ "customerId": 5, "themeName": "Dark", "languageName": "English", "notificationName": "All", "isLock": false, "id": 1 }
POST /api/settings/save Save settings (create on first save, update afterwards)
bash
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

The plans shown in the app's plan picker and purchase screen. Read-only β€” plans are created and edited in the admin panel only, never from the app, so there is no create/update/delete here. No token required: the app shows plans during registration, before the customer has an account. Only active plans are returned.
GET /api/plans/getall Active plans in display order
bash
curl -X GET "https://bizbook.nopcypher.com/api/plans/getall"
response
[
  { "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.

GET /api/plans/getbyid One active plan by id
bash
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.

Rendering a plan card: when 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

Which plan the signed-in customer is on, and every plan they've held. Call 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.
GET /api/membership/getcurrent The customer's current plan
bash
curl -X GET "https://bizbook.nopcypher.com/api/membership/getcurrent" \
  -H "Authorization: Bearer YOUR_TOKEN"
response
{ "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.

POST /api/membership/selectplan Choose or change plan
bash
curl -X POST "https://bizbook.nopcypher.com/api/membership/selectplan" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"planId":2}'
response
(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.

GET /api/membership/gethistory Every plan the customer has held
bash
curl -X GET "https://bizbook.nopcypher.com/api/membership/gethistory" \
  -H "Authorization: Bearer YOUR_TOKEN"
response
[
  { "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.

Registration: 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

Reference data for the location pickers, served from a JSON file rather than the database β€” 67 countries, 1,955 states. Read-only. The usual flow is 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.
GET /api/countries/getall Every country, alphabetical by name
bash
curl -X GET "https://bizbook.nopcypher.com/api/countries/getall" \
  -H "Authorization: Bearer YOUR_TOKEN"
response
[
  { "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.

GET /api/countries/getstates States of one country
bash
curl -X GET "https://bizbook.nopcypher.com/api/countries/getstates?country=IN" \
  -H "Authorization: Bearer YOUR_TOKEN"
response
[
  { "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.

Which value to store: country 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

Website content β€” privacy policy, terms, help and contact β€” written by the administrator and served to the app so the wording can change without shipping a new build. These endpoints need no token, unlike every other module: the app has to show the privacy policy and terms before the user has an account, and Google Play requires the policy to be reachable without signing in. Read-only β€” pages are created and edited in the admin panel.
GET /api/pages/getall All published pages (no body)
bash
curl -X GET "https://bizbook.nopcypher.com/api/pages/getall"
response
[
  { "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.

GET /api/pages/getbyslug One page with its full HTML body
bash
curl -X GET "https://bizbook.nopcypher.com/api/pages/getbyslug?slug=privacy-policy"
response
{ "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.

GET /api/pages/getbyid Same as getbyslug, by numeric id
bash
curl -X GET "https://bizbook.nopcypher.com/api/pages/getbyid?id=1"
Integrating: 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.

StatusWhenBody
400Validation failed β€” bad field value, missing id on update, invalid OTP/mobile, bad reference id{"message":"..."}
401No token sent{"success":false,"message":"Authorization is required."}
401Invalid / expired token, wrong credentials{"success":false,"message":"Invalid or expired session. Login again."}
404Record not found or already deleted{"message":"... not found."}
409Duplicate β€” label name or mobile number{"message":"... already exists."}