Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/FerchoSG/healthcare-web/llms.txt

Use this file to discover all available pages before exploring further.

CitaBox uses JWT bearer authentication. When you log in, the API returns a signed access token. You pass that token in an Authorization header on every subsequent request. A second header, x-clinic-id, tells the API which clinic’s data to scope the request to. Both values are managed automatically by the web app, and this page explains exactly how they work — useful if you are integrating with the API directly.
Never expose your access token in client-side logs, error reports, or public repositories. Anyone with a valid token can make authenticated requests on your behalf until the token expires or is cleared.

Login flow

1

POST credentials to /auth/login

Send your email and password to the login endpoint. This request does not require an Authorization header.
curl -X POST https://api.citabox.app/auth/login \
  -H "Content-Type: application/json" \
  -d '{"email": "doctor@example.com", "password": "your-password"}'
2

Receive the access token

A successful login returns an access_token and the list of clinic memberships your account belongs to.
{
  "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "memberships": [
    {
      "clinic_id": "a1b2c3d4-...",
      "clinic_name": "Clínica Integral San Carlos",
      "clinic_slug": "san-carlos",
      "role": "DOCTOR",
      "specialty": "Medicina general"
    }
  ]
}
The web app stores the token in localStorage under the key access_token using setAccessToken(). If the login response contains only one membership, that clinic is selected automatically. If there are multiple memberships, a clinic picker is shown.
3

Pass the token in the Authorization header

Include the token as a Bearer token in every authenticated request:
curl https://api.citabox.app/appointments \
  -H "Authorization: Bearer <your-token>" \
  -H "x-clinic-id: <your-clinic-id>"
The API client builds this header automatically from the in-memory accessToken value, falling back to localStorage.getItem("access_token") if the in-memory value is not set.
4

Pass your clinic ID in the x-clinic-id header

All clinic-scoped endpoints require the x-clinic-id header. The value is the clinic_id UUID from your membership. The web app stores it in localStorage under clinic_id and injects it via setClinicId().
curl https://api.citabox.app/auth/me \
  -H "Authorization: Bearer <your-token>" \
  -H "x-clinic-id: a1b2c3d4-e5f6-7890-abcd-ef1234567890"

User profile

After setting the clinic context, the app calls GET /auth/me to load the authenticated user’s full profile. The response shape is:
interface MeResponse {
  id: string;
  first_name: string;
  last_name: string;
  email: string;
  active_membership: ClinicMembershipInfo | null;
  memberships: ClinicMembershipInfo[];
}

interface ClinicMembershipInfo {
  clinic_id: string;
  clinic_name: string;
  clinic_slug: string;
  role: Role; // "SUPER_ADMIN" | "ADMIN" | "DOCTOR" | "STAFF"
  specialty: string | null;
}
The active_membership field reflects the clinic currently selected via x-clinic-id. The memberships array contains all clinics the user belongs to, which is used to populate the clinic picker.
CitaBox handles expired or invalid tokens automatically. When any API response returns an HTTP 401 Unauthorized status, the client calls clearAuth(), which removes both access_token and clinic_id from memory and from localStorage. The user is redirected to the login screen on the next render cycle.You do not need to implement token refresh logic. Simply catch the 401, clear local state, and prompt the user to log in again.
// From lib/api-client.ts
if (res.status === 401) clearAuth();
throw new HttpError(res.status, data as ApiError);
CitaBox does not currently implement silent token refresh. If a session expires while the app is open, the user will be asked to log in again.
Users with multiple clinic memberships can switch clinic context at any time from the top header. Switching calls setClinicId(newClinicId), which updates localStorage and the in-memory value, then refetches the user profile via GET /auth/me with the new x-clinic-id.
// From app/page.tsx
const handleClinicSwitch = async (clinicId: string) => {
  setClinicId(clinicId)
  const me = await fetchMe()
  const user = meToAuthUser(me)
  setAuthUser(user)
}
After switching, the user’s role may be different in the new clinic. The app updates the active view to match the default view for the new role (dashboard for admins, front-desk for receptionist, schedule for doctors).
If you are integrating via the API, switching clinics is as simple as changing the x-clinic-id header value in your next request. No new login is required.

Next steps

Quickstart

Walk through the full onboarding flow and create your first appointment.

API reference

Explore all available endpoints with request and response schemas.

Roles and dashboards

Understand how roles — ADMIN, STAFF, DOCTOR — map to views and permissions.

Online booking

Let patients book without an account using the public booking portal.

Build docs developers (and LLMs) love