---
title: "Typeform Connector"
description: "Complete Typeform integration guide for syncing form responses, surveys, and conversational data collection with Brevo through Tajo."
url: https://tajo.io/docs/connectors/custom/typeform/
markdown: https://tajo.io/docs/connectors/custom/typeform.md
lang: en-US
robots: noindex
---

# Typeform Connector

Connector status: Planned Not built yet. Tajo does not run this connector today.

| Source field | Destination field | Sample value |
| --- | --- | --- |
| `record.id` | `source_id` | `record_1042` |
| `record.updated_at` | `updated_at` | `2026-10-18T08:00:00Z` |
| `record.value` | `value` | `sample_value` |

Connect Typeform to Brevo through Tajo to automatically sync form responses, capture leads from conversational forms, and trigger marketing automations based on survey submissions and quiz results.

## Overview

| Property | Value |
| --- | --- |
| **Platform** | Typeform |
| **Category** | Forms & Surveys (Custom) |
| **Setup Complexity** | Easy |
| **Official Integration** | No |
| **Data Synced** | Responses, Contacts, Events, Forms |
| **Auth Method** | OAuth 2.0 / Personal Access Token |

## Features

- **Real-time response sync** - Automatically capture form submissions via webhooks
- **Contact creation** - Create or update Brevo contacts from form responses
- **Lead scoring** - Use quiz scores and form data for lead qualification
- **Hidden Fields** - Pass customer data via Hidden Fields for personalized forms
- **Conditional mapping** - Map different form fields based on response logic
- **Multi-form support** - Connect multiple typeforms to different Brevo lists

## Prerequisites

Before you begin, ensure you have:

1. A Typeform account (Basic plan or above for webhooks)
2. A Personal Access Token from [Typeform Account Settings](https://admin.typeform.com/account#/section/tokens)
3. A Brevo account with API access
4. A Tajo account with connector permissions

## Authentication

### Personal Access Token

```bash
# Generate a token at https://admin.typeform.com/account#/section/tokens
export TYPEFORM_ACCESS_TOKEN=tfp_your_personal_access_token
export TAJO_API_KEY=your_tajo_api_key
export BREVO_API_KEY=your_brevo_api_key
```

### OAuth 2.0

```javascript
// OAuth 2.0 Authorization Flow
const authUrl = 'https://api.typeform.com/oauth/authorize?' +
  new URLSearchParams({
    client_id: process.env.TYPEFORM_CLIENT_ID,
    redirect_uri: 'https://your-app.com/callback',
    scope: 'forms:read responses:read webhooks:write accounts:read',
    state: generateState()
  });

// Exchange authorization code for access token
const tokenResponse = await fetch('https://api.typeform.com/oauth/token', {
  method: 'POST',
  headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
  body: new URLSearchParams({
    grant_type: 'authorization_code',
    code: authorizationCode,
    client_id: process.env.TYPEFORM_CLIENT_ID,
    client_secret: process.env.TYPEFORM_CLIENT_SECRET,
    redirect_uri: 'https://your-app.com/callback'
  })
});
```

## Configuration

### Basic Setup

```yaml
connectors:
  typeform:
    enabled: true
    access_token: "${TYPEFORM_ACCESS_TOKEN}"

    forms:
      - form_id: "abc123"
        list_id: 5
        mapping:
          email_field: "email"
          name_field: "full_name"
      - form_id: "xyz789"
        list_id: 6
        mapping:
          email_field: "work_email"

    sync:
      responses: true
      contacts: true
      events: true

    webhook:
      enabled: true
      secret: "${TYPEFORM_WEBHOOK_SECRET}"
```

### Field Mapping

```yaml
field_mapping:
  # Map Typeform field references to Brevo attributes
  email: email
  name: FIRSTNAME
  company: COMPANY
  phone: SMS
  score: LEAD_SCORE
  quiz_result: QUIZ_SCORE
  nps_rating: NPS_SCORE
  feedback: LAST_FEEDBACK
```

## API Endpoints

| Endpoint | Method | Description |
| --- | --- | --- |
| `https://api.typeform.com/forms` | GET | List all forms |
| `https://api.typeform.com/forms/{form_id}` | GET | Retrieve a form |
| `https://api.typeform.com/forms` | POST | Create a form |
| `https://api.typeform.com/forms/{form_id}` | PUT | Update a form |
| `https://api.typeform.com/forms/{form_id}/responses` | GET | Retrieve responses |
| `https://api.typeform.com/forms/{form_id}/responses` | DELETE | Delete responses |
| `https://api.typeform.com/forms/{form_id}/webhooks/{tag}` | PUT | Create/update webhook |
| `https://api.typeform.com/forms/{form_id}/webhooks/{tag}` | GET | Get webhook |
| `https://api.typeform.com/forms/{form_id}/webhooks` | GET | List webhooks |

## Code Examples

### Initialize Connector

```javascript
import { TajoClient } from '@tajo/sdk';

const tajo = new TajoClient({
  apiKey: process.env.TAJO_API_KEY,
  brevoApiKey: process.env.BREVO_API_KEY
});

await tajo.connectors.connect('typeform', {
  accessToken: process.env.TYPEFORM_ACCESS_TOKEN,
  forms: ['abc123', 'xyz789']
});
```

### Retrieve Form Responses

```javascript
// Fetch responses using the Responses API
const response = await fetch(
  'https://api.typeform.com/forms/abc123/responses?' +
    new URLSearchParams({
      page_size: 25,
      since: '2024-01-01T00:00:00Z',
      completed: 'true'
    }),
  {
    headers: {
      'Authorization': `Bearer ${process.env.TYPEFORM_ACCESS_TOKEN}`
    }
  }
);

const data = await response.json();

// Sync each response to Brevo
for (const item of data.items) {
  const answers = item.answers;
  const email = answers.find(a => a.field.ref === 'email')?.email;

  if (email) {
    await tajo.contacts.sync({
      email,
      attributes: {
        FIRSTNAME: answers.find(a => a.field.ref === 'name')?.text,
        LEAD_SCORE: item.calculated?.score || 0
      },
      listIds: [5]
    });
  }
}
```

### Set Up Webhooks

```javascript
// Register a webhook for real-time response notifications
await fetch(
  'https://api.typeform.com/forms/abc123/webhooks/tajo-sync',
  {
    method: 'PUT',
    headers: {
      'Authorization': `Bearer ${process.env.TYPEFORM_ACCESS_TOKEN}`,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      url: 'https://api.example.com/webhooks/typeform',
      enabled: true,
      secret: process.env.TYPEFORM_WEBHOOK_SECRET
    })
  }
);
```

Caution

The `example.com` address above is a placeholder until the Tajo endpoint is available.

### Handle Webhook Events

```javascript
app.post('/webhooks/typeform', async (req, res) => {
  // Verify webhook signature
  const signature = req.headers['typeform-signature'];
  const isValid = verifyTypeformSignature(
    req.rawBody, signature, process.env.TYPEFORM_WEBHOOK_SECRET
  );

  if (!isValid) return res.status(401).send('Unauthorized');

  const { form_response } = req.body;

  await tajo.connectors.handleWebhook('typeform', {
    topic: 'form_response',
    payload: form_response
  });

  res.status(200).send('OK');
});
```

## Rate Limits

| Endpoint | Rate Limit | Notes |
| --- | --- | --- |
| Create API | 2 requests/sec | Form creation and updates |
| Responses API | 2 requests/sec | Response retrieval |
| Webhooks API | 2 requests/sec | Webhook management |
| All endpoints | 120 requests/min | Global rate limit |

Response Pagination

The Responses API returns a maximum of 1,000 responses per request. Use the `before` or `after` cursor parameters for pagination when retrieving large response sets.

## Troubleshooting

| Issue | Cause | Solution |
| --- | --- | --- |
| Webhook not received | Webhook disabled | Enable webhook in Typeform dashboard |
| Missing responses | Filter applied | Check `since`/`until` and `completed` params |
| Auth error 401 | Token expired | Generate new Personal Access Token |
| Rate limit 429 | Too many requests | Implement request throttling |
| Empty answers | Optional fields | Handle null/undefined answer values |

### Debug Mode

```yaml
connectors:
  typeform:
    debug: true
    log_level: verbose
    log_webhooks: true
    log_responses: true
```

## Best Practices

1. **Use webhooks** - Prefer webhooks over polling for real-time response capture
2. **Validate signatures** - Always verify webhook signatures for security
3. **Use Hidden Fields** - Pre-populate known customer data in forms
4. **Map field references** - Use stable field `ref` values instead of field IDs
5. **Handle partial responses** - Account for optional and skipped questions
6. **Set up retry logic** - Implement idempotent webhook processing

## Security

- **OAuth 2.0** - Scoped token-based authentication
- **Webhook signatures** - SHA-256 HMAC signature validation
- **HTTPS only** - All API endpoints require TLS
- **Token scoping** - Request minimum required OAuth scopes
- **Secret management** - Store tokens in environment variables or secret managers
- **GDPR compliance** - Use the Delete Responses API for data erasure requests

## Related Resources

- [Calendly Connector](https://tajo.io/docs/connectors/custom/calendly)
- [Zapier Connector](https://tajo.io/docs/connectors/custom/zapier)
- [Customer Sync Skill](https://tajo.io/docs/skills/data-sync/customer-sync)
- [Typeform Developer Documentation](https://www.typeform.com/developers/)

## Open-Source Implementation Map

No official open-source repository was found in the current Tajo connector catalog for Typeform. Keep this page focused on the verified public API contract and vendor documentation until an official schema, SDK, MCP server, or public integration repository is available.

### Tajo Revamp Checklist

- Verify authentication and scope requirements against the vendor documentation before each connector release.
- Document primary sync objects, external IDs, pagination strategy, and rate limits explicitly.
- Add smoke tests from public API examples rather than undocumented behavior.
- Capture webhook signature verification and replay protection when the vendor supports webhooks.
- Record gaps where no official public repository or schema exists so future maintainers know what still needs source-backed validation.
