Typeform 连接器
通过 Tajo 将 Typeform 连接到 Brevo,自动同步表单回复,从对话式表单中捕获线索,并根据调查提交和测验结果触发营销自动化。
概览
| 属性 | 值 |
|---|---|
| 平台 | Typeform |
| 类别 | 表单与调查(自定义) |
| 设置复杂度 | 简单 |
| 官方集成 | 否 |
| 同步数据 | 回复、联系人、事件、表单 |
| 认证方式 | OAuth 2.0 / 个人访问令牌 |
功能
- 实时回复同步 - 通过 Webhook 自动捕获表单提交
- 联系人创建 - 从表单回复创建或更新 Brevo 联系人
- 线索评分 - 使用测验评分和表单数据进行线索资格筛选
- 隐藏字段 - 通过隐藏字段传递已知客户数据,实现个性化表单
- 条件映射 - 基于回复逻辑映射不同的表单字段
- 多表单支持 - 将多个 Typeform 连接到不同的 Brevo 列表
前提条件
开始之前,请确保您已具备:
- Typeform 账户(基础版或以上,Webhook 功能需要)
- 来自 Typeform 账户设置 的个人访问令牌
- 具有 API 访问权限的 Brevo 账户
- 具有连接器权限的 Tajo 账户
认证
个人访问令牌
# Generate a token at https://admin.typeform.com/account#/section/tokensexport TYPEFORM_ACCESS_TOKEN=tfp_your_personal_access_tokenexport TAJO_API_KEY=your_tajo_api_keyexport BREVO_API_KEY=your_brevo_api_keyOAuth 2.0
// OAuth 2.0 Authorization Flowconst 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 tokenconst 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' })});配置
基础设置
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: # 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_FEEDBACKAPI 端点
| 端点 | 方法 | 描述 |
|---|---|---|
https://api.typeform.com/forms | GET | 列出所有表单 |
https://api.typeform.com/forms/{form_id} | GET | 检索表单 |
https://api.typeform.com/forms | POST | 创建表单 |
https://api.typeform.com/forms/{form_id} | PUT | 更新表单 |
https://api.typeform.com/forms/{form_id}/responses | GET | 检索回复 |
https://api.typeform.com/forms/{form_id}/responses | DELETE | 删除回复 |
https://api.typeform.com/forms/{form_id}/webhooks/{tag} | PUT | 创建/更新 Webhook |
https://api.typeform.com/forms/{form_id}/webhooks/{tag} | GET | 获取 Webhook |
https://api.typeform.com/forms/{form_id}/webhooks | GET | 列出 Webhook |
代码示例
初始化连接器
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']});检索表单回复
// Fetch responses using the Responses APIconst 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 Brevofor (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] }); }}设置 Webhook
// Register a webhook for real-time response notificationsawait 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.tajo.io/webhooks/typeform', enabled: true, secret: process.env.TYPEFORM_WEBHOOK_SECRET }) });处理 Webhook 事件
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');});速率限制
| 端点 | 速率限制 | 说明 |
|---|---|---|
| 创建 API | 2 请求/秒 | 表单创建和更新 |
| 回复 API | 2 请求/秒 | 回复检索 |
| Webhook API | 2 请求/秒 | Webhook 管理 |
| 所有端点 | 120 请求/分钟 | 全局速率限制 |
回复分页
回复 API 每次请求最多返回 1,000 条回复。检索大量回复集时,使用 before 或 after 游标参数进行分页。
故障排除
| 问题 | 原因 | 解决方案 |
|---|---|---|
| 未收到 Webhook | Webhook 已禁用 | 在 Typeform 控制台中启用 Webhook |
| 回复缺失 | 应用了过滤条件 | 检查 since/until 和 completed 参数 |
| 认证错误 401 | 令牌已过期 | 生成新的个人访问令牌 |
| 速率限制 429 | 请求过多 | 实施请求限流 |
| 答案为空 | 可选字段 | 处理 null/undefined 答案值 |
调试模式
connectors: typeform: debug: true log_level: verbose log_webhooks: true log_responses: true最佳实践
- 使用 Webhook - 优先使用 Webhook 而非轮询,实现实时回复捕获
- 验证签名 - 始终验证 Webhook 签名以确保安全
- 使用隐藏字段 - 在表单中预填充已知的客户数据
- 映射字段引用 - 使用稳定的字段
ref值而非字段 ID - 处理部分回复 - 考虑可选和跳过的问题
- 设置重试逻辑 - 实施幂等的 Webhook 处理
安全
- OAuth 2.0 - 范围化的基于令牌的认证
- Webhook 签名 - SHA-256 HMAC 签名验证
- 仅 HTTPS - 所有 API 端点需要 TLS
- 令牌范围 - 请求最低所需的 OAuth 范围
- 密钥管理 - 在环境变量或密钥管理器中存储令牌
- GDPR 合规 - 使用删除回复 API 处理数据删除请求