npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

medos-sdk

v1.2.1

Published

Medos SDK for managing appointments, meetings, and calendars in apps

Readme

Medos SDK

npm version License TypeScript

A JavaScript/TypeScript SDK for integrating healthcare appointment booking into your applications. Built for clinics, hospitals, and healthcare platforms.

✨ Features

  • 🎨 Powerful Theming System - Customize appearance with built-in themes or create your own
  • ⚛️ React & Vanilla JS - Works with React or pure JavaScript
  • 🔒 Secure Authentication - API key and session token support
  • 📱 Responsive Design - Mobile-first, works on all screen sizes
  • 🎯 TypeScript-First - Full type safety and IntelliSense support
  • Accessible - WCAG compliant components

Installation

npm install medos-sdk

Table of Contents

Quick Start

React

import { MedosThemeProvider, AppointmentCalender } from "medos-sdk/react";

function App() {
  return (
    <MedosThemeProvider theme="modern">
      <AppointmentCalender onError={(err) => console.error(err)} />
    </MedosThemeProvider>
  );
}

Vanilla JavaScript

import { initAppointmentCalendar } from "medos-sdk/vanilla";

initAppointmentCalendar({
  containerId: "appointment-widget",
  apiKey: "your-api-key",
  theme: "modern", // or 'default'
});

HTML/CSS/JS

<!DOCTYPE html>
<html>
  <head>
    <link rel="stylesheet" href="path/to/widget.css" />
  </head>
  <body>
    <div id="appointment-calendar"></div>
    <script src="path/to/widget.js"></script>
    <script>
      window.MedosAppointmentCalendar.init({
        containerId: "appointment-calendar",
        apiKey: "your-api-key",
      });
    </script>
  </body>
</html>

Getting Started

Authentication

The SDK supports two authentication methods:

Server-Side (API Key)

Use this method for backend services and server-side rendering.

import { MedosClient } from "medos-sdk";

await MedosClient.init({
  apiKey: "your-api-key",
});

Client-Side (Session Token)

Use this method for frontend applications. Obtain the session token from your backend.

import { MedosClient } from "medos-sdk";

await MedosClient.initWithSession({
  sessionToken: "user-session-token",
});

Usage

Fetch Clinic Addresses and Doctors

Retrieve all available clinic locations with their associated doctors.

const result = await MedosClient.fetchAllAddressesAndDoctors();

Response:

{
  totalAddresses: 5,
  totalDoctors: 12,
  workspaceId: "workspace-123",
  addresses: [
    {
      id: "addr-1",
      completeAddress: "123 Medical Center, New York, NY 10001",
      addressLine1: "123 Medical Center",
      city: "New York",
      state: "NY",
      country: "USA",
      zipcode: "10001",
      doctors: [
        {
          id: "doc-1",
          name: "Dr. John Smith",
          email: "[email protected]",
          specialty: "Cardiology"
        }
      ]
    }
  ]
}

Fetch Available Slots

Get available appointment time slots for a specific doctor.

const slots = await MedosClient.fetchAppointments(
  "workspace-123", // workspaceId
  "addr-1", // addressId
  "doc-1", // doctorId
  "2025-11-16" // appointmentDate (YYYY-MM-DD)
);

Response:

[
  {
    start: "2025-11-16T10:00:00",
    end: "2025-11-16T10:30:00",
    id: "slot-1",
  },
  {
    start: "2025-11-16T11:00:00",
    end: "2025-11-16T11:30:00",
    id: "slot-2",
  },
];

Book an Appointment

Create a new appointment booking.

import { AppointmentService } from "medos-sdk";

const appointment = await AppointmentService.createAppointment({
  workspaceAddressId: "addr-1",
  doctorId: "doc-1",
  mode: "OFFLINE",
  appointmentDate: "2025-11-16",
  fromDateTimeTs: "10:00",
  toDateTimeTs: "10:30",
  consultationCharge: "100",
  type: "CONSULTATION",
  source: "SDK_POWERED_WEBSITE",
  patientPayload: {
    firstName: "Jane",
    lastName: "Doe",
    email: "[email protected]",
    countryCode: "+1",
    phoneNumber: "5551234567",
    age: 30,
    gender: "FEMALE",
  },
  patientAddress: {
    addressLine1: "456 Patient Street",
    city: "New York",
    state: "NY",
    country: "USA",
    zipcode: "10001",
    landmark: "Near Central Park",
  },
});

Optional Fields:

| Field | Default Value | Description | | -------------------- | ----------------------- | -------------------------------------------- | | mode | "OFFLINE" | Consultation mode: "OFFLINE" or "ONLINE" | | consultationCharge | "0" | Consultation fee as string | | type | "CONSULTATION" | Appointment type | | source | "SDK_POWERED_WEBSITE" | Source identifier |

Phone Verification

Implement OTP-based phone number verification for patients.

Send OTP

await MedosClient.sendPhoneVerificationOtp({
  countryCode: "+1",
  phoneNumber: "5551234567",
});

Verify OTP

const result = await MedosClient.verifyPhoneVerificationOtp({
  countryCode: "+1",
  phoneNumber: "5551234567",
  otp: "123456",
});

TypeScript

The SDK is written in TypeScript and provides comprehensive type definitions.

import {
  MedosClient,
  AppointmentService,
  BookAppointmentPayload,
  AddressesResponse,
  PatientPayload,
  PatientAddressPayload,
} from "medos-sdk";

const payload: BookAppointmentPayload = {
  workspaceAddressId: "addr-1",
  doctorId: "doc-1",
  appointmentDate: "2025-11-16",
  fromDateTimeTs: "10:00",
  toDateTimeTs: "10:30",
  patientPayload: {
    firstName: "John",
    lastName: "Doe",
    countryCode: "+1",
    phoneNumber: "5551234567",
  },
  patientAddress: {
    addressLine1: "123 Main Street",
    city: "New York",
    state: "NY",
    country: "USA",
    zipcode: "10001",
  },
};

const appointment = await AppointmentService.createAppointment(payload);

Type Definitions

BookAppointmentPayload

{
  workspaceAddressId: string | number;
  doctorId: string | number;
  appointmentDate: string;           // Format: "YYYY-MM-DD"
  fromDateTimeTs: string;            // Format: "HH:MM"
  toDateTimeTs: string;              // Format: "HH:MM"
  mode?: "OFFLINE" | "ONLINE";       // Default: "OFFLINE"
  consultationCharge?: string;       // Default: "0"
  type?: "CONSULTATION" | string;    // Default: "CONSULTATION"
  source?: string;                   // Default: "SDK_POWERED_WEBSITE"
  patientPayload: PatientPayload;
  patientAddress: PatientAddressPayload;  // Required
}

PatientPayload

{
  firstName: string;
  lastName: string;
  countryCode: string;
  phoneNumber: string;
  email?: string;
  age?: number;
  gender?: "MALE" | "FEMALE" | "OTHER";
}

PatientAddressPayload

{
  addressLine1?: string;
  city?: string;
  state?: string;
  country?: string;
  zipcode?: string;
  landmark?: string;
}

React Integration

Pre-built appointment calendar component for React applications.

import { AppointmentCalender } from "medos-sdk";

function BookingPage() {
  return <AppointmentCalender />;
}

The component automatically uses the initialized MedosClient instance.

Using React-specific exports

For better tree-shaking and to avoid React dependency conflicts:

import { AppointmentCalender } from "medos-sdk/react";

Vanilla JavaScript / HTML Integration

For websites using plain HTML, CSS, and JavaScript (no React), use the vanilla widget. The SDK provides two widgets: Appointment Booking and Enquiry Form.

Installation Options

Option 1: NPM Package (Recommended)

npm install medos-sdk

After building, you'll find the widget files in:

  • dist/vanilla/widget.js - JavaScript bundle (UMD format)
  • dist/vanilla/widget.css - Base stylesheet
  • dist/vanilla/widget-themed.css - Advanced theming stylesheet

Option 2: CDN Integration

Load directly from CDN (replace with actual CDN URL when available):

<!-- CSS -->
<link
  rel="stylesheet"
  href="https://cdn.jsdelivr.net/npm/medos-sdk@latest/dist/vanilla/widget.css"
/>

<!-- JavaScript -->
<script src="https://cdn.jsdelivr.net/npm/medos-sdk@latest/dist/vanilla/widget.js"></script>

Appointment Booking Widget

Basic Usage

<!DOCTYPE html>
<html>
  <head>
    <link rel="stylesheet" href="path/to/widget.css" />
  </head>
  <body>
    <div id="appointment-calendar"></div>

    <script src="path/to/widget.js"></script>
    <script>
      // Method 1: Global API (Recommended)
      window.MedosAppointmentCalendar.init({
        containerId: "appointment-calendar",
        apiKey: "your-api-key",
        onError: (err) => {
          console.error("Error:", err);
          alert("An error occurred. Please try again.");
        },
        onSuccess: () => {
          console.log("Appointment booked successfully!");
        },
      });

      // Method 2: Class-based API (Alternative)
      // const widget = new window.MedosAppointmentWidget('appointment-calendar', {
      //   apiKey: 'your-api-key'
      // });
    </script>
  </body>
</html>

CDN Integration Example

<!DOCTYPE html>
<html>
  <head>
    <link
      rel="stylesheet"
      href="https://cdn.jsdelivr.net/npm/medos-sdk@latest/dist/vanilla/widget.css"
    />
  </head>
  <body>
    <div id="appointment-widget"></div>

    <script src="https://cdn.jsdelivr.net/npm/medos-sdk@latest/dist/vanilla/widget.js"></script>
    <script>
      window.MedosAppointmentCalendar.init({
        containerId: "appointment-widget",
        sessionToken: "your-session-token", // Obtained from your server
        baseURL: "https://api.medos.one/v1",
        onError: (err) => console.error(err),
        onSuccess: () => console.log("Success!"),
      });
    </script>
  </body>
</html>

Enquiry Form Widget

Basic Usage

<!DOCTYPE html>
<html>
  <head>
    <link rel="stylesheet" href="path/to/widget.css" />
  </head>
  <body>
    <div id="enquiry-form"></div>

    <script src="path/to/widget.js"></script>
    <script>
      // Method 1: Global API (Recommended)
      window.MedosEnquiryForm.init({
        containerId: "enquiry-form",
        apiKey: "your-api-key",
        onError: (err) => console.error(err),
        onSuccess: (enquiry) => {
          console.log("Enquiry submitted:", enquiry);
          alert("Thank you! Your enquiry has been submitted.");
        },
      });

      // Method 2: Class-based API (Alternative)
      // const widget = new window.MedosEnquiryWidget('enquiry-form', {
      //   apiKey: 'your-api-key'
      // });
    </script>
  </body>
</html>

Widget Step Flow

Appointment Booking Steps

The appointment widget follows this exact step sequence (matching React component):

  1. Step 0: Phone Verification - Country code selection, phone input, OTP verification
  2. Step 1: Booking Option Selection - Session packs vs. new appointment (auto-skipped if no packages)
  3. Step 2: Location & Doctor Selection - Address and doctor selection with chief complaint
  4. Step 3: Date & Time Selection - Calendar, consultation mode, and time slot selection
  5. Step 4: Patient Selection - Choose existing patient or create new
  6. Step 5: Patient Details Form - Patient information and address (for new patients)
  7. Step 6: Appointment Summary - Review all details and cost breakdown
  8. Step 7: Success Confirmation - Confirmation with appointment details

Enquiry Form Steps

  1. Step 1: Contact Information - Name, email, phone number
  2. Step 2: Inquiry Details - Subject and detailed message
  3. Step 3: Contact Preference - Preferred contact method (email, phone, both)
  4. Step 4: Success Confirmation - Submission confirmation

Configuration Options

Complete API reference for widget initialization:

interface WidgetOptions {
  containerId: string; // Required: ID of container element
  apiKey?: string; // Optional: API key for authentication
  sessionToken?: string; // Optional: Session token (alternative to apiKey)
  baseURL?: string; // Optional: API base URL (default: https://api.medos.one/v1)
  onError?: (error: Error) => void; // Optional: Error callback
  onSuccess?: (data?: any) => void; // Optional: Success callback
  onStepChange?: (step: number) => void; // Optional: Step change callback
  theme?: "default" | "modern" | string; // Optional: Theme selection
}

Configuration Examples

Basic Configuration:

window.MedosAppointmentCalendar.init({
  containerId: "appointment-widget",
  apiKey: "your-api-key",
});

Advanced Configuration with Callbacks:

window.MedosAppointmentCalendar.init({
  containerId: "appointment-widget",
  sessionToken: "user-session-token",
  baseURL: "https://api.medos.one/v1",
  theme: "modern",
  onError: (error) => {
    console.error("Widget error:", error);
    // Show user-friendly error message
    document.getElementById("error-message").textContent =
      "Unable to load appointment booking. Please try again.";
    document.getElementById("error-message").style.display = "block";
  },
  onSuccess: (appointment) => {
    console.log("Appointment booked successfully", appointment);
    // Redirect or show success message
    window.location.href = "/appointment-confirmation";
  },
  onStepChange: (step) => {
    console.log("Current step:", step);
    // Track user progress for analytics
    if (typeof analytics !== "undefined") {
      analytics.track("appointment_step_change", { step });
    }
  },
});

Environment-Specific Configuration:

const isProduction = window.location.hostname !== "localhost";
const config = {
  containerId: "appointment-widget",
  baseURL: isProduction
    ? "https://api.medos.one/v1"
    : "https://dev-api.medos.one/v1",
  sessionToken: await getSessionToken(), // Fetch from your backend
  onError: (error) => handleWidgetError(error),
};

window.MedosAppointmentCalendar.init(config);

Authentication Methods

Using Session Token (Recommended for Production)

For better security, obtain the session token server-side:

// Fetch session token from your backend
async function initializeWidget() {
  try {
    const response = await fetch("/api/get-session-token");
    const { sessionToken } = await response.json();

    window.MedosAppointmentCalendar.init({
      containerId: "appointment-calendar",
      sessionToken: sessionToken,
      baseURL: "https://api.medos.one/v1",
      onError: (err) => console.error(err),
    });
  } catch (error) {
    console.error("Failed to get session token:", error);
  }
}

initializeWidget();

Using API Key (Development Only)

window.MedosAppointmentCalendar.init({
  containerId: "appointment-calendar",
  apiKey: "your-api-key", // Only for development/testing
  onError: (err) => console.error(err),
});

Server-Side Integration Examples

PHP Integration

<?php
// Get session token from your backend
function getSessionTokenFromBackend() {
    // Your implementation to get session token
    // This should call your backend API that exchanges API key for session token
    $apiKey = 'your-api-key';
    $response = file_get_contents('https://api.medos.one/v1/auth/session', false, stream_context_create([
        'http' => [
            'method' => 'POST',
            'header' => "Authorization: Bearer $apiKey\r\nContent-Type: application/json\r\n",
            'content' => json_encode(['apiKey' => $apiKey])
        ]
    ]));
    $data = json_decode($response, true);
    return $data['sessionToken'];
}

$sessionToken = getSessionTokenFromBackend();
?>
<!DOCTYPE html>
<html>
<head>
    <link rel="stylesheet" href="path/to/widget.css">
</head>
<body>
    <div id="appointment-calendar"></div>
    <script src="path/to/widget.js"></script>
    <script>
        window.MedosAppointmentCalendar.init({
            containerId: 'appointment-calendar',
            sessionToken: '<?php echo htmlspecialchars($sessionToken); ?>',
            onError: function(err) {
                console.error('Error:', err);
                alert('An error occurred. Please try again.');
            },
            onSuccess: function() {
                console.log('Appointment booked successfully!');
                // Redirect to confirmation page
                window.location.href = '/appointment-confirmation.php';
            }
        });
    </script>
</body>
</html>

Node.js/Express Integration

// Backend route to get session token
app.get("/api/session-token", async (req, res) => {
  try {
    const response = await axios.post("https://api.medos.one/v1/auth/session", {
      apiKey: process.env.MEDOS_API_KEY,
    });
    res.json({ sessionToken: response.data.sessionToken });
  } catch (error) {
    res.status(500).json({ error: "Failed to get session token" });
  }
});
<!-- Frontend HTML -->
<!DOCTYPE html>
<html>
  <head>
    <link rel="stylesheet" href="/dist/vanilla/widget.css" />
  </head>
  <body>
    <div id="appointment-widget"></div>
    <script src="/dist/vanilla/widget.js"></script>
    <script>
      fetch("/api/session-token")
        .then((response) => response.json())
        .then((data) => {
          window.MedosAppointmentCalendar.init({
            containerId: "appointment-widget",
            sessionToken: data.sessionToken,
            onError: (err) => console.error(err),
            onSuccess: () => console.log("Success!"),
          });
        })
        .catch((error) => console.error("Failed to initialize widget:", error));
    </script>
  </body>
</html>

Multiple Widgets on Same Page

You can use multiple widgets independently on the same page:

<!DOCTYPE html>
<html>
  <head>
    <link rel="stylesheet" href="path/to/widget.css" />
  </head>
  <body>
    <!-- Appointment Widget -->
    <div id="appointment-widget"></div>

    <!-- Enquiry Widget -->
    <div id="enquiry-widget"></div>

    <script src="path/to/widget.js"></script>
    <script>
      // Initialize appointment widget
      window.MedosAppointmentCalendar.init({
        containerId: "appointment-widget",
        apiKey: "your-api-key",
        onSuccess: () => console.log("Appointment booked!"),
      });

      // Initialize enquiry widget
      window.MedosEnquiryForm.init({
        containerId: "enquiry-widget",
        apiKey: "your-api-key",
        onSuccess: (enquiry) => console.log("Enquiry submitted:", enquiry),
      });
    </script>
  </body>
</html>

Global API Reference

After loading the widget script, these global objects are available:

// Global initialization functions
window.MedosAppointmentCalendar.init(options); // Appointment widget
window.MedosEnquiryForm.init(options); // Enquiry form widget

// Widget classes for advanced usage
window.MedosAppointmentWidget; // Appointment widget class
window.MedosEnquiryWidget; // Enquiry widget class

Widget Lifecycle Management

Destroying Widgets

// For class-based initialization
const widget = new window.MedosAppointmentWidget("container", options);
// Later...
widget.destroy(); // Clean up event listeners and DOM

// For global API initialization
// Widgets are automatically cleaned up when container is removed from DOM

Reinitializing Widgets

// Clear container and reinitialize
const container = document.getElementById("appointment-widget");
container.innerHTML = ""; // Clear existing widget

window.MedosAppointmentCalendar.init({
  containerId: "appointment-widget",
  apiKey: "your-api-key",
});

Theme Customization

The SDK provides comprehensive theming capabilities through CSS variables. Choose between two CSS files based on your customization needs:

Basic Theming (widget.css)

For simple customization with minimal variables:

<link rel="stylesheet" href="dist/vanilla/widget.css" />
<style>
  .my-theme {
    --medos-primary-color: #7c3aed;
    --medos-primary-color-hover: #6d28d9;
    --medos-bg-color: #ffffff;
    --medos-text-color: #1f2937;
  }
</style>
<div id="widget" class="my-theme"></div>

Advanced Theming (widget-themed.css)

For comprehensive design system customization:

<link rel="stylesheet" href="dist/vanilla/widget-themed.css" />
<style>
  .my-advanced-theme {
    /* Colors */
    --medos-color-primary: #7c3aed;
    --medos-color-background: #ffffff;
    --medos-color-text: #1f2937;

    /* Typography */
    --medos-typography-font-family: "Georgia", serif;
    --medos-typography-font-size-md: 18px;

    /* Spacing & Layout */
    --medos-spacing-md: 16px;
    --medos-radius-md: 20px;
    --medos-shadow-lg: 0 20px 40px rgba(124, 58, 237, 0.15);
  }
</style>
<div id="widget" class="my-advanced-theme"></div>

Dynamic Theme Switching

// Apply theme programmatically
const container = document.getElementById("widget-container");

// Method 1: CSS classes
container.classList.add("dark-theme");

// Method 2: Direct CSS variables
container.style.setProperty("--medos-color-primary", "#7c3aed");
container.style.setProperty("--medos-color-background", "#1f2937");

// Method 3: Theme objects
const themes = {
  purple: {
    "--medos-color-primary": "#7c3aed",
    "--medos-color-secondary": "#a855f7",
  },
  green: {
    "--medos-color-primary": "#10b981",
    "--medos-color-secondary": "#34d399",
  },
};

function applyTheme(themeName) {
  const theme = themes[themeName];
  Object.entries(theme).forEach(([property, value]) => {
    container.style.setProperty(property, value);
  });
}

Theme Examples

Explore comprehensive theming examples in the examples/ directory:

  • theme-customization-basic.html - Basic CSS variable overrides
  • theme-customization-advanced.html - Multiple theme comparisons
  • theme-customization-javascript.html - Dynamic theme switching
  • theme-comparison.html - Side-by-side CSS file comparison
  • enquiry-form-theming.html - Enquiry form specific themes

Available CSS Variables

Basic Variables (widget.css):

  • --medos-primary-color, --medos-primary-color-hover
  • --medos-bg-color, --medos-bg-color-secondary
  • --medos-text-color, --medos-text-color-secondary
  • --medos-border-color, --medos-border-radius

Complete Variables (widget-themed.css):

  • Colors: 15+ color tokens for comprehensive theming
  • Typography: Font family, sizes, weights
  • Spacing: Consistent spacing scale (xs, sm, md, lg, xl)
  • Layout: Border radius, shadows, transitions

See examples/README-THEME-CUSTOMIZATION.md for complete documentation.

Troubleshooting Guide

Common Issues and Solutions

1. Widget Not Loading

Problem: Widget container remains empty, no errors in console.

Solutions:

// Check if widget script loaded
if (typeof window.MedosAppointmentCalendar === "undefined") {
  console.error("Widget script not loaded. Check script src path.");
}

// Ensure container exists
const container = document.getElementById("your-container-id");
if (!container) {
  console.error("Container element not found. Check containerId.");
}

// Wait for DOM ready
document.addEventListener("DOMContentLoaded", function () {
  window.MedosAppointmentCalendar.init({
    containerId: "appointment-widget",
    apiKey: "your-api-key",
  });
});

2. Authentication Errors

Problem: "Invalid API key" or "Authentication failed" errors.

Solutions:

// Verify API key format
const apiKey = "your-api-key";
if (!apiKey || apiKey === "your-api-key") {
  console.error("Please replace with your actual API key");
}

// Use session token for production
window.MedosAppointmentCalendar.init({
  containerId: "widget",
  sessionToken: "your-session-token", // More secure
  baseURL: "https://api.medos.one/v1",
});

// Check API endpoint
fetch("https://api.medos.one/v1/health")
  .then((response) => console.log("API accessible:", response.ok))
  .catch((error) => console.error("API not accessible:", error));

3. CSS Styling Issues

Problem: Widget appears unstyled or has layout issues.

Solutions:

<!-- Ensure CSS is loaded before JavaScript -->
<link rel="stylesheet" href="path/to/widget.css" />
<script src="path/to/widget.js"></script>

<!-- Check for CSS conflicts -->
<style>
  /* Ensure widget container has proper styling */
  #appointment-widget {
    width: 100%;
    max-width: 800px;
    margin: 0 auto;
  }

  /* Reset any conflicting styles */
  .medos-appointment-container * {
    box-sizing: border-box;
  }
</style>

4. Network/CORS Errors

Problem: "CORS policy" or network request failures.

Solutions:

// Check baseURL configuration
window.MedosAppointmentCalendar.init({
  containerId: "widget",
  apiKey: "your-api-key",
  baseURL: "https://api.medos.one/v1", // Ensure correct URL
  onError: (error) => {
    if (error.message.includes("CORS")) {
      console.error("CORS error: Ensure your domain is whitelisted");
    }
    if (error.message.includes("Network")) {
      console.error("Network error: Check internet connection and API status");
    }
  },
});

// Test API connectivity
async function testAPIConnection() {
  try {
    const response = await fetch("https://api.medos.one/v1/health");
    console.log("API Status:", response.status);
  } catch (error) {
    console.error("Cannot reach API:", error);
  }
}

5. Multiple Widget Conflicts

Problem: Multiple widgets interfering with each other.

Solutions:

// Use unique container IDs
window.MedosAppointmentCalendar.init({
  containerId: "appointment-widget-1", // Unique ID
  apiKey: "your-api-key",
});

window.MedosEnquiryForm.init({
  containerId: "enquiry-widget-1", // Different unique ID
  apiKey: "your-api-key",
});

// Clean up widgets when needed
const widget = new window.MedosAppointmentWidget("container", options);
// Later...
widget.destroy(); // Prevents memory leaks

6. Mobile/Responsive Issues

Problem: Widget doesn't display properly on mobile devices.

Solutions:

<!-- Ensure viewport meta tag -->
<meta name="viewport" content="width=device-width, initial-scale=1.0" />

<style>
  /* Responsive container */
  .widget-container {
    width: 100%;
    max-width: 100vw;
    padding: 10px;
    box-sizing: border-box;
  }

  /* Mobile-specific adjustments */
  @media (max-width: 768px) {
    .widget-container {
      padding: 5px;
    }
  }
</style>

7. Theme Not Applying

Problem: Custom CSS variables not taking effect.

Solutions:

/* Ensure proper CSS specificity */
.my-theme .medos-appointment-container {
  --medos-color-primary: #7c3aed !important;
}

/* Or apply to widget container directly */
#appointment-widget {
  --medos-color-primary: #7c3aed;
  --medos-color-background: #ffffff;
}
// Apply theme programmatically
const container = document.getElementById("appointment-widget");
container.style.setProperty("--medos-color-primary", "#7c3aed");

// Verify theme variables are applied
const computedStyle = getComputedStyle(container);
const primaryColor = computedStyle.getPropertyValue("--medos-color-primary");
console.log("Applied primary color:", primaryColor);

Debugging Tips

Enable Debug Mode:

// Add debug logging
window.MedosAppointmentCalendar.init({
  containerId: "widget",
  apiKey: "your-api-key",
  debug: true, // Enable debug mode if available
  onError: (error) => {
    console.error("Widget Error Details:", {
      message: error.message,
      stack: error.stack,
      timestamp: new Date().toISOString(),
    });
  },
  onStepChange: (step) => {
    console.log("Step changed to:", step);
  },
});

Check Widget State:

// Inspect widget instance
const container = document.getElementById("appointment-widget");
const widgetInstance = container._medosWidget; // Internal reference
if (widgetInstance) {
  console.log("Widget state:", widgetInstance.getState());
}

// Check global objects
console.log("Available globals:", {
  MedosAppointmentCalendar: typeof window.MedosAppointmentCalendar,
  MedosEnquiryForm: typeof window.MedosEnquiryForm,
  MedosAppointmentWidget: typeof window.MedosAppointmentWidget,
  MedosEnquiryWidget: typeof window.MedosEnquiryWidget,
});

Network Debugging:

// Monitor API calls
const originalFetch = window.fetch;
window.fetch = function (...args) {
  console.log("API Request:", args[0]);
  return originalFetch
    .apply(this, args)
    .then((response) => {
      console.log("API Response:", response.status, response.url);
      return response;
    })
    .catch((error) => {
      console.error("API Error:", error);
      throw error;
    });
};

Performance Optimization

Lazy Loading:

// Load widget only when needed
function loadWidget() {
  if (!document.getElementById("widget-script")) {
    const script = document.createElement("script");
    script.id = "widget-script";
    script.src = "path/to/widget.js";
    script.onload = () => {
      window.MedosAppointmentCalendar.init({
        containerId: "appointment-widget",
        apiKey: "your-api-key",
      });
    };
    document.head.appendChild(script);
  }
}

// Load on user interaction
document
  .getElementById("book-appointment-btn")
  .addEventListener("click", loadWidget);

Resource Optimization:

<!-- Preload critical resources -->
<link rel="preload" href="path/to/widget.css" as="style" />
<link rel="preload" href="path/to/widget.js" as="script" />

<!-- Use appropriate CSS file for your needs -->
<!-- widget.css for basic theming (smaller file) -->
<link rel="stylesheet" href="dist/vanilla/widget.css" />

<!-- widget-themed.css for advanced theming (larger file) -->
<link rel="stylesheet" href="dist/vanilla/widget-themed.css" />

Getting Help

If you encounter issues not covered in this guide:

  1. Check Browser Console: Look for error messages and warnings
  2. Verify Network Tab: Check if API requests are successful
  3. Test with Examples: Compare with working examples in examples/ directory
  4. Check Version Compatibility: Ensure you're using compatible versions
  5. Review Documentation: Check docs/VANILLA_WIDGET.md for additional details

Common Error Messages:

  • "Container element not found" → Check containerId parameter
  • "Invalid API key" → Verify API key or use session token
  • "Network request failed" → Check internet connection and API status
  • "Widget already initialized" → Clear container before reinitializing
  • "Theme variables not applied" → Check CSS specificity and variable names

Package Exports

The SDK provides multiple entry points for different use cases:

  • medos-sdk - Default export (includes React components)
  • medos-sdk/react - React-specific exports
  • medos-sdk/vanilla - Vanilla JS exports (ES modules)
  • medos-sdk/core - Core services only (no framework dependencies)
  • medos-sdk/widget - Widget bundle with CSS

Examples and Documentation

Comprehensive examples and documentation are available:

HTML Examples (examples/ directory)

  • vanilla-appointment-booking.html - Basic appointment widget with local files
  • cdn-appointment-booking.html - CDN integration example with fallback strategies
  • enquiry-form.html - Enquiry form widget with both local and CDN options
  • theme-customization-basic.html - Basic CSS variable overrides and theming
  • theme-customization-advanced.html - Advanced theming with multiple theme comparisons
  • theme-customization-javascript.html - Dynamic theme switching and programmatic theming
  • theme-comparison.html - Side-by-side comparison of CSS files
  • enquiry-form-theming.html - Enquiry form specific theming examples

Documentation (docs/ directory)

  • VANILLA_WIDGET.md - Comprehensive vanilla widget documentation
  • CDN_INTEGRATION.md - Complete CDN integration guide with best practices
  • BUILD.md - Build system and development setup
  • IMPLEMENTATION_STATUS.md - Current implementation status and roadmap

Theme Documentation

  • examples/README-THEME-CUSTOMIZATION.md - Complete theming guide with examples
  • CSS variable reference for both widget.css and widget-themed.css
  • Dynamic theme switching examples and best practices

API Reference

MedosClient

init(config)

Initialize the SDK with an API key (server-side).

Parameters:

  • config.apiKey (string, required) - Your Medos API key
  • config.baseURL (string, optional) - API base URL. Defaults to dev environment

Returns: Promise<void>


initWithSession(config)

Initialize the SDK with a session token (client-side).

Parameters:

  • config.sessionToken (string, required) - Session token
  • config.baseURL (string, optional) - API base URL. Defaults to dev environment

Returns: Promise<void>


fetchAllAddressesAndDoctors()

Fetch all clinic addresses and their associated doctors.

Returns: Promise<AddressesResponse>

Response Type:

{
  totalAddresses?: number;
  totalDoctors?: number;
  workspaceId?: number | string;
  addresses: Array<{
    id: string;
    completeAddress?: string;
    addressLine1?: string;
    city?: string;
    state?: string;
    country?: string;
    zipcode?: string;
    doctors?: Array<{
      id: string;
      name: string;
      email?: string;
      specialty?: string;
    }>;
  }>;
}

fetchAppointments(workspaceId, addressId, doctorId, appointmentDate)

Fetch available appointment slots for a specific doctor.

Parameters:

  • workspaceId (string | number) - Workspace identifier
  • addressId (string | number) - Address identifier
  • doctorId (string | number) - Doctor identifier
  • appointmentDate (string) - Date in YYYY-MM-DD format

Returns: Promise<Slot[]>

Response Type:

Array<{
  start: string; // ISO datetime format
  end: string; // ISO datetime format
  id?: string;
}>;

sendPhoneVerificationOtp(payload)

Send OTP to a phone number for verification.

Parameters:

  • payload.countryCode (string) - Country code with + prefix (e.g., "+1")
  • payload.phoneNumber (string) - Phone number without country code

Returns: Promise<any>


verifyPhoneVerificationOtp(payload)

Verify OTP for a phone number.

Parameters:

  • payload.countryCode (string) - Country code with + prefix
  • payload.phoneNumber (string) - Phone number without country code
  • payload.otp (string) - OTP code received

Returns: Promise<any>


AppointmentService

createAppointment(payload)

Create a new appointment booking.

Parameters:

  • payload (BookAppointmentPayload) - Appointment details

Returns: Promise<any>

Error Handling

All SDK methods return Promises and should be wrapped in try-catch blocks.

try {
  await MedosClient.init({ apiKey: "your-api-key" });
  const addresses = await MedosClient.fetchAllAddressesAndDoctors();
} catch (error) {
  console.error("Failed to fetch addresses:", error.message);
}

Requirements

  • Node.js: v14 or higher
  • Browsers: Modern browsers with ES6+ support
  • React: v19 or higher (only required for React components, not for vanilla widget)
  • TypeScript: v5 or higher (optional)

Support

For bug reports and feature requests, please visit our GitHub Issues.

License

UNLICENSED

Author

Pooranjoy Bhattacharya


Built for healthcare providers worldwide.