Skip to main content

Overview

Checks whether a specific user has connected their Google Calendar to your platform. Useful before attempting to schedule meetings.

Authentication

Requires Platform API Key in the X-API-Key header.

Request

GET https://api.syncline.run/v1/platform/users/status?email=alice@example.com

Query Parameters

email
string
required
Email address of the user to check

Response

User Connected

{
  "connected": true,
  "user_email": "alice@example.com",
  "google_id": "103847562910384756291",
  "connected_at": "2025-01-15T10:30:00Z",
  "timezone": "America/New_York",
  "preferences": {
    "work_hours": {
      "monday": { "enabled": true, "start": "09:00", "end": "17:00" }
    },
    "buffer_minutes": 15,
    "energy_pattern": "morning_person"
  },
  "calendar_access": "read_write"
}

User Not Connected

{
  "connected": false,
  "user_email": "alice@example.com",
  "message": "User has not connected their calendar"
}

Response Fields

connected
boolean
Whether the user has connected their calendar
user_email
string
The email address that was checked
google_id
string
Google account ID (only if connected)
connected_at
string
ISO 8601 timestamp of when they connected (only if connected)
preferences
object
User’s scheduling preferences (only if connected)

Use Cases

Pre-Flight Check Before Scheduling

async function scheduleWithCheck(attendees, meetingDetails) {
  // Check all attendees are connected
  for (const email of attendees) {
    const status = await checkUserStatus(email);

    if (!status.connected) {
      // Get OAuth URL for this user
      const { oauth_url } = await getOAuthURL(email);

      return {
        error: 'user_not_connected',
        user_email: email,
        message: `${email} needs to connect their calendar`,
        oauth_url
      };
    }
  }

  // All connected - proceed with scheduling
  return await scheduleMeeting(attendees, meetingDetails);
}

Conditional UI Rendering

// React component
function ScheduleMeetingButton({ attendeeEmail }) {
  const [status, setStatus] = useState(null);

  useEffect(() => {
    checkStatus(attendeeEmail).then(setStatus);
  }, [attendeeEmail]);

  if (!status) return <LoadingSpinner />;

  if (!status.connected) {
    return (
      <button onClick={() => window.open(status.oauth_url)}>
        Connect Calendar First →
      </button>
    );
  }

  return (
    <button onClick={scheduleMeeting}>
      Schedule Meeting ✓
    </button>
  );
}

Batch Connection Status

// Check multiple users at once
async function checkMultipleUsers(emails) {
  const checks = await Promise.all(
    emails.map(email => checkUserStatus(email))
  );

  const connected = checks.filter(c => c.connected);
  const notConnected = checks.filter(c => !c.connected);

  return {
    all_connected: notConnected.length === 0,
    connected_count: connected.length,
    not_connected_users: notConnected.map(c => c.user_email)
  };
}

// Usage
const status = await checkMultipleUsers([
  'alice@example.com',
  'bob@example.com',
  'charlie@example.com'
]);

if (!status.all_connected) {
  console.log('These users need to connect:');
  status.not_connected_users.forEach(email => {
    console.log(`- ${email}`);
  });
}

Connection Health Monitoring

// Check connection health for all your users
async function auditConnections() {
  const { users } = await getAllUsers();

  const statuses = await Promise.all(
    users.map(u => checkUserStatus(u.email))
  );

  const stats = {
    total: users.length,
    connected: statuses.filter(s => s.connected).length,
    not_connected: statuses.filter(s => !s.connected).length,
    connection_rate: 0
  };

  stats.connection_rate = (stats.connected / stats.total * 100).toFixed(1);

  return stats;
}

// Run daily
const stats = await auditConnections();
console.log(`Connection Rate: ${stats.connection_rate}%`);
console.log(`Connected: ${stats.connected}/${stats.total} users`);

Error Responses

Invalid Email

{
  "error": "Invalid email format",
  "message": "Please provide a valid email address"
}

Missing Email Parameter

{
  "error": "Email parameter required",
  "message": "Please provide an email query parameter"
}

Best Practices

Cache Connection Status

// Cache status for 5 minutes to avoid repeated API calls
const connectionCache = new Map();

async function checkUserStatusCached(email) {
  const cached = connectionCache.get(email);

  if (cached && Date.now() - cached.timestamp < 5 * 60 * 1000) {
    return cached.status;
  }

  const status = await checkUserStatus(email);

  connectionCache.set(email, {
    status,
    timestamp: Date.now()
  });

  return status;
}

Handle Disconnections Gracefully

async function scheduleOrPromptConnection(attendees, details) {
  const checks = await Promise.all(
    attendees.map(email => checkUserStatus(email))
  );

  const notConnected = checks.filter(c => !c.connected);

  if (notConnected.length > 0) {
    // Don't fail silently - prompt users to connect
    const oauthUrls = await Promise.all(
      notConnected.map(c => getOAuthURL(c.user_email))
    );

    return {
      success: false,
      needs_connection: notConnected.map((c, i) => ({
        email: c.user_email,
        oauth_url: oauthUrls[i].oauth_url
      })),
      message: 'Some users need to connect their calendars'
    };
  }

  // All connected - schedule
  return await scheduleMeeting(attendees, details);
}

Proactive Notification

// Notify users when their connection expires
async function notifyDisconnectedUsers() {
  const { users } = await getAllUsers();

  for (const user of users) {
    const status = await checkUserStatus(user.email);

    if (!status.connected && user.was_previously_connected) {
      // Send email notification
      await sendEmail({
        to: user.email,
        subject: 'Reconnect your calendar',
        body: `Your calendar connection has expired. Reconnect here: ${oauth_url}`
      });
    }
  }
}