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

# Routing Forms

> Build multi-step forms that collect data and route visitors to the right destination

Routing forms collect visitor data through single-page or multi-step funnels, then route the visitor to a meeting type, external URL, custom page, or contact form based on configurable rules.

## Key Concepts

| Concept | Description |
| - | - |
| **Data Field** | Reusable form input (text, email, select, etc.) scoped to your company |
| **Routing Form** | Container for fields, funnel steps, and routing rules |
| **Funnel Step** | One page/slide in a multi-step form |
| **Qualifier** | Routing rule with conditions and an action |
| **Recipient** | Person who received a one-time form link |

## Structure Types

| Type | Description |
| - | - |
| `FORM_ONLY` | Single-page form |
| `FUNNEL_WITH_FORM` | Multi-step funnel followed by a final form page |
| `FUNNEL_ONLY` | Multi-step funnel without a final form |

## Create a Routing Form

Create a form with inline data fields, funnel steps, and routing rules in a single request:

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST "https://api.meetergo.com/v4/routing-form" \
    -H "Authorization: Bearer YOUR_API_KEY" \
    -H "x-meetergo-api-user-id: {userId}" \
    -H "Content-Type: application/json" \
    -d '{
      "name": "Lead Qualification",
      "structureType": "FUNNEL_WITH_FORM",
      "showProgressBar": true,
      "funnelSteps": [
        {
          "dataFields": [
            {
              "dataField": {
                "label": "Company Size",
                "fieldType": "select",
                "options": [
                  { "label": "1-10", "value": "small" },
                  { "label": "11-100", "value": "medium" },
                  { "label": "100+", "value": "enterprise" }
                ]
              }
            }
          ]
        }
      ],
      "fields": [
        { "dataFieldId": 1, "order": 0 },
        { "dataFieldId": 4, "order": 1 }
      ],
      "qualifiers": [
        {
          "routingAction": "eventRedirect",
          "meetingTypeId": "your-meeting-type-uuid",
          "expression": {
            "operator": "and",
            "operands": [{
              "operator": "equals",
              "target": "attendeeOther",
              "customTarget": "Company Size",
              "value": "enterprise"
            }]
          }
        },
        {
          "routingAction": "customPage",
          "isFallback": true,
          "customPageContent": {
            "en": "Thanks! We will be in touch.",
            "de": "Danke! Wir melden uns bei Ihnen."
          }
        }
      ]
    }'
  ```

  ```javascript JavaScript theme={null}
  const response = await fetch('https://api.meetergo.com/v4/routing-form', {
    method: 'POST',
    headers: {
      'Authorization': 'Bearer YOUR_API_KEY',
      'x-meetergo-api-user-id': userId,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      name: 'Lead Qualification',
      structureType: 'FUNNEL_WITH_FORM',
      showProgressBar: true,
      funnelSteps: [{
        dataFields: [{
          dataField: {
            label: 'Company Size',
            fieldType: 'select',
            options: [
              { label: '1-10', value: 'small' },
              { label: '11-100', value: 'medium' },
              { label: '100+', value: 'enterprise' }
            ]
          }
        }]
      }],
      fields: [
        { dataFieldId: 1, order: 0 },
        { dataFieldId: 4, order: 1 }
      ],
      qualifiers: [{
        routingAction: 'eventRedirect',
        meetingTypeId: 'your-meeting-type-uuid',
        expression: {
          operator: 'and',
          operands: [{
            operator: 'equals',
            target: 'attendeeOther',
            customTarget: 'Company Size',
            value: 'enterprise'
          }]
        }
      }, {
        routingAction: 'customPage',
        isFallback: true,
        customPageContent: { en: 'Thanks! We will be in touch.' }
      }]
    })
  });

  const routingForm = await response.json();
  ```
</CodeGroup>

## Cascade Creation

When creating or updating a routing form, data fields can be **referenced by ID** or **created inline**:

```javascript theme={null}
// Reference an existing data field
{ dataFieldId: 42, order: 0 }

// Create a new data field inline
{
  dataField: {
    label: 'Industry',
    fieldType: 'select',
    options: [
      { label: 'Tech', value: 'tech' },
      { label: 'Finance', value: 'finance' }
    ]
  },
  order: 1
}
```

This works in both `fields` (form fields) and `funnelSteps[].dataFields` (funnel step fields).

## Data Fields

Data fields are reusable inputs scoped to your company.

### Input Fields

| Type | Description |
| - | - |
| `email` | Email with validation |
| `phone` | Phone number (optional country picker via `style` and `defaultCountryCode`) |
| `text-single` | Single-line text |
| `text-multi` | Multi-line textarea |
| `number` | Numeric input (supports `min`/`max`) |
| `url` | URL input with validation |
| `date` | General date picker |
| `date-of-birth` | Date of birth picker (max date = today) |
| `time` | Time picker (HH:MM) |
| `yes-no` | Binary yes/no button choice |
| `rating` | Star rating (1–max stars, max defaults to 5) |
| `currency` | Numeric currency input (`placeholder` holds the currency symbol, default: €) |
| `location` | Geolocation capture (stores `"lat,lng"` string) |

### Selection Fields

| Type | Description |
| - | - |
| `select` | Dropdown (supports `displayStyle`: `default`, `card-icon`, `card-image`) |
| `radio` | Radio buttons (supports `displayStyle`) |
| `checkbox-single` | Single checkbox (e.g. consent) |
| `checkbox-multi` | Multiple checkboxes (supports `displayStyle`) |
| `slide` | Funnel page with visual option cards (requires `slideOptions`) |

### Composite Fields

| Type | Description | Options |
| - | - | - |
| `contact` | Configurable contact data (name, email, phone, address) | `contactOptions` |
| `bank-details` | SEPA/bank details (IBAN always shown, BIC/account holder/signature configurable) | `bankDetailsOptions` |
| `license-plate` | Vehicle license plate input (all countries or Germany-only) | `licensePlateOptions` |

### File & Document Fields

| Type | Description | Options |
| - | - | - |
| `file` | File upload (Growth+) | `fileFieldOptions` |
| `image` | Image-only upload with optional camera capture | `fileFieldOptions` |
| `signature` | Canvas-based e-signature (stored as base64 PNG) | `requireSignatureOtp` |
| `pdf-template` | PDF template with drag-and-drop field placement and optional signature | `pdfTemplateOptions` |
| `file-download` | Display-only — shows library files the respondent can download | `fileDownloadOptions` |

### Display-Only Fields

These fields do not collect input. They are used for layout and content within forms.

| Type | Description | Notes |
| - | - | - |
| `heading` | Section heading | Uses `label` as text, `headingLevel` (1–6, default 2) |
| `separator` | Visual separator line | No configuration needed |
| `page-break` | Splits form into pages | Optional title via `label` |
| `info-text` | Rich text block (Markdown/HTML) | Uses `label` as content |
| `info-image` | Image block | Uses `label` as the image URL |
| `info-video` | Video embed (YouTube/Vimeo/Loom) | Uses `label` as the video URL |

### Create Data Field

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST "https://api.meetergo.com/v4/data-field" \
    -H "Authorization: Bearer YOUR_API_KEY" \
    -H "x-meetergo-api-user-id: {userId}" \
    -H "Content-Type: application/json" \
    -d '{
      "label": "Budget Range",
      "fieldType": "select",
      "required": true,
      "options": [
        { "label": "< $10k", "value": "small" },
        { "label": "$10k-$50k", "value": "medium" },
        { "label": "$50k+", "value": "large" }
      ],
      "locales": [
        { "locale": "de", "label": "Budgetbereich" }
      ]
    }'
  ```

  ```javascript JavaScript theme={null}
  const response = await fetch('https://api.meetergo.com/v4/data-field', {
    method: 'POST',
    headers: {
      'Authorization': 'Bearer YOUR_API_KEY',
      'x-meetergo-api-user-id': userId,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      label: 'Budget Range',
      fieldType: 'select',
      required: true,
      options: [
        { label: '< $10k', value: 'small' },
        { label: '$10k-$50k', value: 'medium' },
        { label: '$50k+', value: 'large' }
      ]
    })
  });
  ```
</CodeGroup>

## Routing Rules (Qualifiers)

Qualifiers determine where a visitor goes after submitting the form. They are evaluated in order; the first match wins.

### Routing Actions

| Action | Description | Required Field |
| - | - | - |
| `eventRedirect` | Redirect to a meeting type | `meetingTypeId` (optionally `meetingTypeUserId` to target a specific user) |
| `customPage` | Show localized thank-you page | `customPageContent` (optionally `customFormTitle`, `showThankYouOnCustomPage`) |
| `externalRedirect` | Redirect to URL | `externalRedirectLink` |
| `contactForm` | Show contact form | `contactFormEmail` |
| `requestCallback` | Request callback via queue | `queueId` |
| `instantCall` | Start instant video call | -- |
| `formRedirect` | Redirect to another routing form | -- |

### Condition Expressions

Conditions use a nested AND/OR tree:

```json theme={null}
{
  "expression": {
    "operator": "and",
    "operands": [
      {
        "operator": "equals",
        "target": "attendeeOther",
        "customTarget": "Company Size",
        "value": "enterprise"
      },
      {
        "operator": "or",
        "operands": [
          { "operator": "contains", "target": "attendeeEmail", "value": "@bigcorp.com" },
          { "operator": "equals", "target": "attendeeOther", "customTarget": "Budget", "value": "large" }
        ]
      }
    ]
  }
}
```

**Operators:** `equals`, `notEqual`, `contains`, `notContains`, `startsWith`, `blank`, `notBlank`, `lessThan`, `greaterThan`, `lessThanOrEqual`, `moreThanOrEqual`, `containsAny`, `containsNone`

**Targets:** `attendeeEmail`, `attendeeFullname`, `attendeeFirstname`, `attendeeLastname`, `attendeePhone`, `attendeePolicyAccepted`, `attendeeReceiveReminders`, `attendeeLanguage`, `attendeeTimezone`, `attendeeOther` (use `customTarget` for custom field name)

### Fallback Qualifier

If no qualifier has `isFallback: true`, a default "Thanks for submitting" custom page is auto-created.

## Updating with Declarative Sync

When updating via `PATCH`, nested arrays use different strategies:

* **Qualifiers**: Declarative sync -- items with `id` are updated, without `id` are created, missing items are removed
* **Funnel Steps & Fields**: Full replace -- the array you send replaces the current set

```javascript theme={null}
// Update: keep one qualifier, add another, remove the rest
await fetch(`https://api.meetergo.com/v4/routing-form/${formId}`, {
  method: 'PATCH',
  headers,
  body: JSON.stringify({
    qualifiers: [
      { id: 'existing-qualifier-uuid', routingAction: 'customPage' },
      { routingAction: 'eventRedirect', meetingTypeId: 'new-mt-uuid',
        expression: { operator: 'and', operands: [/*...*/] } }
    ]
  })
});
```

## Sending Forms

Send a routing form to a recipient via email, SMS, or generate a one-time link.

### Delivery Methods

| Method | Description | Required |
| - | - | - |
| `email` (default) | Sends email with one-time link | `email` |
| `sms` | Sends SMS with one-time link | `phone` |
| `link` | Generates one-time link only | -- |

### Send via Email

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST "https://api.meetergo.com/v4/routing-form/{formId}/send" \
    -H "Authorization: Bearer YOUR_API_KEY" \
    -H "x-meetergo-api-user-id: {userId}" \
    -H "Content-Type: application/json" \
    -d '{
      "recipientName": "John Smith",
      "email": "john@example.com",
      "message": "Please fill out this form before our meeting.",
      "deliveryMethod": "email"
    }'
  ```

  ```javascript JavaScript theme={null}
  const response = await fetch(
    `https://api.meetergo.com/v4/routing-form/${formId}/send`,
    {
      method: 'POST',
      headers,
      body: JSON.stringify({
        recipientName: 'John Smith',
        email: 'john@example.com',
        message: 'Please fill out this form before our meeting.',
        deliveryMethod: 'email'
      })
    }
  );

  const { publicUrl, status } = await response.json();
  // publicUrl: "https://cal.meetergo.com/f/r/abc123..."
  // status: "sent"
  ```
</CodeGroup>

### Generate One-Time Link (No Notification)

```javascript theme={null}
const { publicUrl } = await fetch(
  `https://api.meetergo.com/v4/routing-form/${formId}/send`,
  {
    method: 'POST',
    headers,
    body: JSON.stringify({
      recipientName: 'Partner',
      deliveryMethod: 'link'
    })
  }
).then(r => r.json());

// Distribute publicUrl however you like
```

The response always includes `publicUrl` regardless of delivery method.

### Shareable Public Link (Unlimited)

For unlimited-access forms, set a `slug`:

```javascript theme={null}
await fetch(`https://api.meetergo.com/v4/routing-form/${formId}`, {
  method: 'PATCH',
  headers,
  body: JSON.stringify({ slug: 'my-lead-form' })
});
// Public URL: https://cal.meetergo.com/f/my-lead-form
```

## One-Time Fill

When sent to a recipient, each link can only be submitted once:

1. **Send** -- `POST /v4/routing-form/:id/send` creates a recipient with a unique token
2. **Open** -- Recipient opens the link, `openedAt` is recorded
3. **Submit** -- Recipient submits, `completedAt` is recorded
4. **Blocked** -- Re-submission returns `409 Conflict`

### Track Recipients

```javascript theme={null}
const { recipients } = await fetch(
  `https://api.meetergo.com/v4/routing-form/${formId}/recipients`,
  { headers }
).then(r => r.json());

// Each recipient has: status ("sent" | "opened" | "completed"),
// publicUrl, sentAt, openedAt, completedAt
```

## API Reference

| Method | Endpoint | Description |
| - | - | - |
| `POST` | `/v4/routing-form` | Create routing form |
| `GET` | `/v4/routing-form` | List routing forms |
| `GET` | `/v4/routing-form/:id` | Get routing form |
| `PATCH` | `/v4/routing-form/:id` | Update routing form |
| `DELETE` | `/v4/routing-form/:id` | Delete routing form |
| `POST` | `/v4/routing-form/:id/send` | Send to recipient |
| `GET` | `/v4/routing-form/:id/recipients` | List recipients |
| `POST` | `/v4/data-field` | Create data field |
| `GET` | `/v4/data-field` | List data fields |
| `GET` | `/v4/data-field/:id` | Get data field |
| `PATCH` | `/v4/data-field/:id` | Update data field |
| `DELETE` | `/v4/data-field/:id` | Delete data field |

## Next Steps

<CardGroup cols={2}>
  <Card title="Routing & Round-Robin" icon="arrows-split-up-and-left" href="/developer-docs/core-concepts/routing">
    Distribute bookings across team members
  </Card>

  <Card title="Meeting Types" icon="calendar" href="/developer-docs/core-concepts/meeting-types">
    Configure meeting templates
  </Card>
</CardGroup>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.