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

# Routing Forms

> Qualify leads and route bookings to the right team member or event type based on form responses

Routing Forms allow you to ask qualifying questions before someone books a meeting. Based on their answers, you can route them to the appropriate event type, team member, or even prevent booking if they don't meet criteria.

## Overview

A Routing Form is a multi-step form that:

1. **Collects information**: Ask custom questions to qualify leads
2. **Evaluates responses**: Use conditional logic to determine the best route
3. **Routes to event type**: Direct users to the appropriate booking page
4. **Triggers workflows**: Execute automations based on form submission

```typescript theme={null}
// From schema.prisma:1325
model App_RoutingForms_Form {
  id          String   @id
  name        String   // Form name
  description String?  // Form description
  fields      Json?    // Form fields definition
  routes      Json?    // Routing logic
  disabled    Boolean  @default(false)
  userId      Int      // Owner
  teamId      Int?     // Optional team ownership
  settings    Json?    // Form settings
}
```

<Note>
  Routing Forms are particularly useful for sales teams, support desks, and any scenario where different types of inquiries need different handling.
</Note>

## Creating a Routing Form

<Steps>
  <Step title="Navigate to Routing Forms">
    Go to Apps → Routing Forms (you may need to install the Routing Forms app first)
  </Step>

  <Step title="Create New Form">
    Click "Create Form" and give it a name
  </Step>

  <Step title="Add Fields">
    Add questions to collect information from users
  </Step>

  <Step title="Configure Routes">
    Set up conditional logic to route based on responses
  </Step>

  <Step title="Set Fallback">
    Define what happens if no routes match
  </Step>

  <Step title="Publish Form">
    Share the form URL with your audience
  </Step>
</Steps>

## Form Fields

Routing Forms support various field types:

```typescript theme={null}
// From routing-forms types
type Field = {
  id: string;
  type: "text" | "email" | "phone" | "number" | 
        "textarea" | "select" | "multiselect" | 
        "radio" | "checkbox";
  label: string;
  required: boolean;
  placeholder?: string;
  options?: string[];  // For select, radio, checkbox
};
```

<Tabs>
  <Tab title="Text Input">
    Basic text field for short answers.

    ```typescript theme={null}
    {
      type: "text",
      label: "Company Name",
      required: true,
      placeholder: "Acme Corp"
    }
    ```
  </Tab>

  <Tab title="Select">
    Dropdown with predefined options.

    ```typescript theme={null}
    {
      type: "select",
      label: "Company Size",
      required: true,
      options: ["1-10", "11-50", "51-200", "200+"]
    }
    ```
  </Tab>

  <Tab title="Radio">
    Single choice from multiple options.

    ```typescript theme={null}
    {
      type: "radio",
      label: "Inquiry Type",
      required: true,
      options: ["Sales", "Support", "Partnership", "Other"]
    }
    ```
  </Tab>

  <Tab title="Multi-Select">
    Multiple choices allowed.

    ```typescript theme={null}
    {
      type: "multiselect",
      label: "Interested Services",
      options: ["Consulting", "Training", "Implementation", "Support"]
    }
    ```
  </Tab>
</Tabs>

## Routing Logic

Routes use query-builder logic to evaluate responses:

```typescript theme={null}
// Route structure
type Route = {
  id: string;
  queryValue: {  // Conditional logic
    rules: [
      {
        field: "companySize",
        operator: "equals" | "contains" | "greaterThan" | "lessThan",
        value: string | number
      }
    ],
    combinator: "and" | "or"  // How to combine rules
  };
  action: {
    type: "eventTypeRedirect" | "customPageMessage" | "externalRedirect";
    value: string;  // Event type ID, message, or URL
  };
};
```

### Route Actions

<CardGroup cols={3}>
  <Card title="Event Type Redirect" icon="calendar">
    Send to a specific event type's booking page
  </Card>

  <Card title="Custom Message" icon="message">
    Display a message (e.g., "We'll contact you")
  </Card>

  <Card title="External Redirect" icon="arrow-up-right-from-square">
    Redirect to any external URL
  </Card>
</CardGroup>

## Example Routing Form

### Sales Qualification Form

```typescript theme={null}
{
  name: "Sales Inquiry",
  fields: [
    {
      id: "name",
      type: "text",
      label: "Your Name",
      required: true
    },
    {
      id: "email",
      type: "email",
      label: "Email Address",
      required: true
    },
    {
      id: "companySize",
      type: "select",
      label: "Company Size",
      required: true,
      options: ["1-10", "11-50", "51-200", "200+"]
    },
    {
      id: "budget",
      type: "select",
      label: "Monthly Budget",
      required: true,
      options: ["< $1k", "$1k-$5k", "$5k-$10k", "$10k+"]
    },
    {
      id: "timeline",
      type: "radio",
      label: "When do you need to start?",
      options: ["Immediately", "1-3 months", "3-6 months", "Just exploring"]
    }
  ],
  routes: [
    {
      id: "enterprise",
      queryValue: {
        combinator: "and",
        rules: [
          { field: "companySize", operator: "equals", value: "200+" },
          { field: "budget", operator: "equals", value: "$10k+" }
        ]
      },
      action: {
        type: "eventTypeRedirect",
        value: "enterprise-demo"  // Route to enterprise event type
      }
    },
    {
      id: "midmarket",
      queryValue: {
        combinator: "or",
        rules: [
          { field: "companySize", operator: "equals", value: "51-200" },
          { field: "companySize", operator: "equals", value: "11-50" }
        ]
      },
      action: {
        type: "eventTypeRedirect",
        value: "sales-demo"  // Route to standard sales demo
      }
    },
    {
      id: "exploring",
      queryValue: {
        combinator: "and",
        rules: [
          { field: "timeline", operator: "equals", value: "Just exploring" }
        ]
      },
      action: {
        type: "customPageMessage",
        value: "Thanks for your interest! We'll send you more information via email."
      }
    }
  ],
  fallback: {
    type: "eventTypeRedirect",
    value: "consultation-call"  // Default if no routes match
  }
}
```

## Form Responses

```typescript theme={null}
// From schema.prisma:1354
model App_RoutingForms_FormResponse {
  id           Int      @id
  formId       String
  response     Json     // User's answers
  createdAt    DateTime @default(now)
  
  routedToBookingUid String?  // If routed to booking
  chosenRouteId      String?  // Which route was taken
}
```

Form responses are stored and can be viewed in the form's responses page.

### Response Format

```typescript theme={null}
// Example response
{
  response: {
    "name": { value: "John Doe", label: "John Doe" },
    "email": { value: "john@example.com", label: "john@example.com" },
    "companySize": { value: "51-200", label: "51-200" },
    "budget": { value: "$5k-$10k", label: "$5k-$10k" },
    "timeline": { value: "1-3 months", label: "1-3 months" }
  },
  chosenRouteId: "midmarket",
  routedToBookingUid: "booking_abc123"
}
```

## Workflow Integration

Routing Forms can trigger workflows:

```typescript theme={null}
// From schema.prisma:1610
model WorkflowsOnRoutingForms {
  workflowId    Int
  routingFormId String
  workflow      Workflow
  routingForm   App_RoutingForms_Form
}
```

### Form Workflow Triggers

```typescript theme={null}
// From workflows constants.ts:103
enum WorkflowTriggerEvents {
  FORM_SUBMITTED           // When form is submitted with booking
  FORM_SUBMITTED_NO_EVENT  // When form is submitted without booking
}
```

<Note>
  Workflows can access form response data to personalize notifications based on user answers.
</Note>

## Form Settings

```typescript theme={null}
// Form settings
settings: {
  redirectUrl?: string;              // Custom redirect after submission
  emailNotification?: {
    enabled: boolean;
    recipients: string[];            // Who receives notifications
  };
  requireEmailVerification?: boolean;
  reCaptcha?: {
    enabled: boolean;
  };
}
```

## Queued Responses

If a route requires async processing:

```typescript theme={null}
// From schema.prisma:1381
model App_RoutingForms_QueuedFormResponse {
  id             String   @id
  formId         String
  response       Json
  chosenRouteId  String?
  fallbackAction Json?    // Action if routing fails
  createdAt      DateTime @default(now)
}
```

Queued responses are processed by background jobs.

## Use Cases

### Support Triage

```typescript theme={null}
{
  name: "Support Request",
  fields: [
    { type: "select", label: "Issue Type", 
      options: ["Bug", "Feature Request", "Question", "Account Issue"] },
    { type: "select", label: "Severity", 
      options: ["Critical", "High", "Medium", "Low"] }
  ],
  routes: [
    {
      // Critical bugs go to emergency support
      queryValue: { 
        rules: [
          { field: "issueType", operator: "equals", value: "Bug" },
          { field: "severity", operator: "equals", value: "Critical" }
        ],
        combinator: "and"
      },
      action: { type: "eventTypeRedirect", value: "emergency-support" }
    },
    {
      // Account issues to billing team
      queryValue: { 
        rules: [{ field: "issueType", operator: "equals", value: "Account Issue" }] 
      },
      action: { type: "eventTypeRedirect", value: "billing-support" }
    }
  ]
}
```

### Recruitment Screening

```typescript theme={null}
{
  name: "Interview Request",
  fields: [
    { type: "text", label: "Position" },
    { type: "select", label: "Years of Experience", 
      options: ["0-2", "3-5", "5-10", "10+"] },
    { type: "radio", label: "Work Authorization",
      options: ["Yes", "No", "Requires Sponsorship"] },
    { type: "select", label: "Availability",
      options: ["Immediate", "2 weeks", "1 month", "2+ months"] }
  ],
  routes: [
    {
      // Senior candidates to senior recruiter
      queryValue: {
        rules: [
          { field: "experience", operator: "in", value: ["5-10", "10+"] }
        ]
      },
      action: { type: "eventTypeRedirect", value: "senior-recruiter" }
    },
    {
      // Junior candidates to junior recruiter
      queryValue: {
        rules: [
          { field: "experience", operator: "in", value: ["0-2", "3-5"] }
        ]
      },
      action: { type: "eventTypeRedirect", value: "junior-recruiter" }
    }
  ]
}
```

### Lead Qualification

```typescript theme={null}
{
  name: "Demo Request",
  fields: [
    { type: "email", label: "Work Email" },
    { type: "text", label: "Company" },
    { type: "select", label: "Role", 
      options: ["Developer", "Manager", "Executive", "Other"] },
    { type: "number", label: "Team Size" },
    { type: "checkbox", label: "Which features interest you?",
      options: ["Analytics", "Integrations", "API Access", "Enterprise SSO"] }
  ],
  routes: [
    {
      // Executives with large teams to enterprise sales
      queryValue: {
        combinator: "and",
        rules: [
          { field: "role", operator: "equals", value: "Executive" },
          { field: "teamSize", operator: "greaterThan", value: 50 }
        ]
      },
      action: { type: "eventTypeRedirect", value: "enterprise-sales" }
    },
    {
      // Others to standard demo
      queryValue: { rules: [] },  // Always matches
      action: { type: "eventTypeRedirect", value: "standard-demo" }
    }
  ]
}
```

## Operators Reference

```typescript theme={null}
type Operator = 
  | "equals"           // Exact match
  | "notEquals"        // Not equal
  | "contains"         // String contains
  | "notContains"      // String doesn't contain
  | "greaterThan"      // Number >
  | "greaterThanEqual" // Number >=
  | "lessThan"         // Number <
  | "lessThanEqual"    // Number <=
  | "in"               // Value in array
  | "notIn"            // Value not in array
  | "isEmpty"          // Field is empty
  | "isNotEmpty";      // Field has value
```

## Best Practices

<CardGroup cols={2}>
  <Card title="Keep Forms Short" icon="list">
    Ask only essential qualifying questions. Long forms decrease completion rates.
  </Card>

  <Card title="Provide Clear Options" icon="list-check">
    Use select/radio fields instead of text when possible for easier routing logic.
  </Card>

  <Card title="Set a Fallback" icon="arrows-split-up-and-left">
    Always define a default action if no routes match.
  </Card>

  <Card title="Test Your Logic" icon="flask">
    Submit test responses to verify routes work as expected.
  </Card>
</CardGroup>

## Viewing Form Responses

<Steps>
  <Step title="Open Routing Form">
    Go to your routing forms list and select a form
  </Step>

  <Step title="View Responses Tab">
    Click the "Responses" tab to see all submissions
  </Step>

  <Step title="Filter and Search">
    Filter by date, route taken, or specific answer values
  </Step>

  <Step title="Export Data">
    Export responses as CSV for analysis
  </Step>
</Steps>

## Advanced: Fallback Actions

When no routes match:

```typescript theme={null}
fallback: {
  type: "eventTypeRedirect" | "customPageMessage" | "externalRedirect",
  value: string
}
```

<Warning>
  Always set a fallback action. Users who don't match any route should still receive a response or next step.
</Warning>

## Troubleshooting

### Route Not Triggering

1. **Check field names**: Ensure route conditions reference correct field IDs
2. **Review operators**: Verify operator matches data type (e.g., don't use `greaterThan` on strings)
3. **Test logic**: Use form preview to test with sample data
4. **Check combinators**: Verify `and`/`or` logic is correct

### Form Not Showing

1. **Check disabled status**: Form might be disabled
2. **Verify team membership**: For team forms, ensure user has access
3. **Review URL**: Confirm form URL is correct

## Related Features

* [Workflows](/features/workflows) - Automate actions on form submission
* [Event Types](/features/event-types) - Route to different event types
* [Teams](/features/teams) - Team-level routing forms
