> ## Documentation Index
> Fetch the complete documentation index at: https://docs.thoughtly.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Cal.com integration

> Connect Cal.com to Thoughtly so voice agents can check team availability, book event types, and reschedule or cancel meetings without manual handoffs.

export const IntegrationPage = ({actions, triggers, name, domain, logoOverride}) => {
  const logoOverrides = {
    acuity: 'https://cdn.thoughtly.com/integrations/acuity_scheduling.svg',
    acuityscheduling: 'https://cdn.thoughtly.com/integrations/acuity_scheduling.svg',
    'cal.com': 'https://cdn.thoughtly.com/integrations/cal.com.svg',
    calcom: 'https://cdn.thoughtly.com/integrations/cal.com.svg',
    cal: 'https://cdn.thoughtly.com/integrations/cal.com.svg',
    'fence flow': 'https://cdn.thought.ly/integrations/fence-flow.png',
    fenceflow: 'https://cdn.thought.ly/integrations/fence-flow.png',
    gohighlevel: 'https://cdn.thought.ly/integrations/highlevel.png',
    highlevel: 'https://cdn.thought.ly/integrations/highlevel.png',
    hubspot: 'https://cdn.thought.ly/integrations/hubspot.png',
    keap: 'https://cdn.thoughtly.com/integrations/keap.svg',
    mindbody: 'https://cdn.thoughtly.com/integrations/mindbody.svg',
    pipedrive: 'https://cdn.thoughtly.com/integrations/pipedrive.svg',
    salesforce: 'https://cdn.thoughtly.com/integrations/salesforce.svg',
    slack: 'https://cdn.thoughtly.com/integrations/slack.svg',
    smartsheet: 'https://cdn.thoughtly.com/integrations/smartsheet.svg',
    trello: 'https://cdn.thoughtly.com/integrations/trello.svg',
    zendesk: 'https://cdn.thoughtly.com/integrations/zendesk.svg',
    zoho: 'https://cdn.thoughtly.com/integrations/zoho.svg',
    zoom: 'https://cdn.thoughtly.com/integrations/zoom.svg',
    gmail: 'https://cdn.thoughtly.com/integrations/google-mail.png'
  };
  const normalizeKey = value => (value || '').toString().trim().toLowerCase();
  const normalizeHost = value => {
    if (!value) {
      return '';
    }
    const cleaned = value.replace(/^https?:\/\//, '').replace(/^[^@]+@/, '');
    return cleaned.split(/[/?#]/)[0];
  };
  const getLogoSrc = ({name: logoName, domain: logoDomain, logoOverride}) => {
    if (logoOverride) {
      return logoOverride;
    }
    const nameKey = normalizeKey(logoName);
    const host = normalizeHost(logoDomain);
    const hostKey = normalizeKey(host);
    const hostBase = hostKey.split('.').slice(-2, -1)[0] || '';
    return logoOverrides[nameKey] || logoOverrides[nameKey.replace(/\s+/g, '')] || logoOverrides[hostKey] || logoOverrides[hostBase] || (logoDomain ? `https://logo.clearbit.com/${logoDomain}` : undefined);
  };
  return <div>
		<div className="flex flex-row items-center h-10 pb-4">
			<img src={getLogoSrc({
    name,
    domain,
    logoOverride
  })} className="w-5 rounded-md mr-2 h-5" />
			<div className="text-xl">
				Integrate with <a href={`https://${domain}`} target={"_blank"}><span className="font-bold">{name}</span></a>
			</div>
		</div>

		By integrating Thoughtly with {name}, you can automate tasks and workflows before, during, and after calls. To integrate with {name}, head to the <a href="https://app.thoughtly.com/integration" target="_blank">Integrations</a> page and follow the instructions.

		{triggers && <div>
				<hr />
				<h3>Triggers</h3>

				Triggers are available via <a href="/automations/triggers">Automations</a>. You can use them to start your Automations, such as for initiating a call or sending an SMS.

				{triggers.map(trigger => <div className="text-sm">
						<h4 className="text-gray-600 text-md">{trigger.name}</h4>

						{trigger.description}
					</div>)}
			</div>}

		{actions && actions.length > 0 && <div>
				<hr />
				<h3>Actions</h3>

				Actions are available both via <a href="/agents/nodes">Mid-Call Actions</a> and <a href="/automations/actions">Automations</a>. You can give your Voice Agents access to these Actions so they can perform tasks in {name} during a call, or use them in Automations to automate tasks before and after calls.

				{actions.map((action, i) => <div key={i} className="text-sm">
						<h4 className={`text-gray-600 ${action.deprecated ? 'line-through text-red-500' : ''}`}>
							<span className="text-gray-600">{action.name}</span>
							{action.deprecated && <span className="ml-3 text-xs">(Deprecated)</span>}
						</h4>
						<p className={action.deprecated ? 'text-gray-400' : ''}>
							{action.description}
						</p>
					</div>)}
			</div>}
	</div>;
};

***

<IntegrationPage
  name="Cal.com"
  domain="cal.com"
  actions={[
    {
        "name": "Check Booking Availability",
        "description": "Checks availability for a booking slot or event type.",
    },
    {
        "name": "Create Booking",
        "description": "Creates a booking for a selected time.",
    }
]}
/>

## Using variables with Cal.com actions

All Cal.com actions support [variables](/agents/variables) in their input fields. You can reference variables captured earlier in the conversation to dynamically populate booking details:

* **Attendee information** - Use variables like `{{email}}`, `{{name}}`, or `{{phone}}` for attendee details
* **Event details** - Reference `{{event_type_id}}` or `{{team_id}}` from earlier lookups
* **Scheduling** - Use `{{desired_time}}` or `{{timezone}}` captured from the caller
* **Node references** - Reference data from specific nodes using `Node #[step]: Answer` format

**Example:** If you capture the caller's email at node 3 and their preferred time at node 5, you can use `Node #3: Answer` for the attendee email and `Node #5: Answer` for the booking time in your Cal.com action.

<Note>Variables are automatically resolved when the action runs during the call. Make sure to extract and validate required fields (email, time, timezone) before triggering the booking action.</Note>
