网淘吧来吧,欢迎您!

Tally

2026-03-29 新闻来源:网淘吧 围观:19
电脑广告
手机广告

Tally

通过托管的OAuth认证访问Tally API。管理您Tally账户的表单、提交、工作区和网络钩子。

快速开始

# List your forms
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://gateway.maton.ai/tally/forms')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
req.add_header('User-Agent', 'Maton/1.0')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF

基础URL

https://gateway.maton.ai/tally/{native-api-path}

{native-api-path}替换为实际的Tally API端点路径。网关将请求代理到api.tally.so并自动注入您的OAuth令牌。

认证

所有请求都需要在Authorization头部中包含Maton API密钥,以及User Agent头部:

Authorization: Bearer $MATON_API_KEY
User-Agent: Maton/1.0

环境变量:将您的API密钥设置为MATON_API_KEY

export MATON_API_KEY="YOUR_API_KEY"

获取您的API密钥

  1. 登录或在maton.ai
  2. 创建账户前往
  3. maton.ai/settings

复制您的API密钥

管理您的Tally OAuth连接,请访问https://ctrl.maton.ai

列出连接

python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://ctrl.maton.ai/connections?app=tally&status=ACTIVE')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF

创建连接

python <<'EOF'
import urllib.request, os, json
data = json.dumps({'app': 'tally'}).encode()
req = urllib.request.Request('https://ctrl.maton.ai/connections', data=data, method='POST')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
req.add_header('Content-Type', 'application/json')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF

获取连接

python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://ctrl.maton.ai/connections/{connection_id}')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF

响应:

{
  "connection": {
    "connection_id": "cd54e2b0-f1d0-435e-a97d-f2d6a5c474bf",
    "status": "ACTIVE",
    "creation_time": "2026-02-07T21:00:31.222600Z",
    "last_updated_time": "2026-02-07T21:00:37.821240Z",
    "url": "https://connect.maton.ai/?session_token=...",
    "app": "tally",
    "metadata": {}
  }
}

在浏览器中打开返回的网址以完成OAuth授权。

删除连接

python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://ctrl.maton.ai/connections/{connection_id}', method='DELETE')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF

指定连接

如果您有多个Tally连接,请使用Maton-Connection请求头指定要使用的连接:

python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://gateway.maton.ai/tally/forms')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
req.add_header('Maton-Connection', 'cd54e2b0-f1d0-435e-a97d-f2d6a5c474bf')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF

如果省略,网关将使用默认(最早创建的)活动连接。

API参考

用户

获取当前用户

GET /tally/users/me

响应:

{
  "id": "w2lBkb",
  "firstName": "John",
  "lastName": "Doe",
  "email": "john@example.com",
  "organizationId": "n0Ze8Q",
  "subscriptionPlan": "FREE",
  "createdAt": "2026-02-07T20:58:54.000Z",
  "updatedAt": "2026-02-07T22:50:35.000Z"
}

表单

列出表单

GET /tally/forms

查询参数:

  • 页码- 页码(默认值:1)
  • 限制- 每页项目数(默认值:50)

响应:

{
  "items": [
    {
      "id": "GxdRaQ",
      "name": "Contact Form",
      "workspaceId": "3jW9Q1",
      "organizationId": "n0Ze8Q",
      "status": "PUBLISHED",
      "hasDraftBlocks": false,
      "numberOfSubmissions": 42,
      "createdAt": "2026-02-09T08:36:00.000Z",
      "updatedAt": "2026-02-09T08:36:17.000Z",
      "isClosed": false
    }
  ],
  "page": 1,
  "limit": 50,
  "total": 1,
  "hasMore": false
}

获取表单

GET /tally/forms/{formId}

响应:

{
  "id": "GxdRaQ",
  "name": "Contact Form",
  "workspaceId": "3jW9Q1",
  "status": "PUBLISHED",
  "blocks": [
    {
      "uuid": "11111111-1111-1111-1111-111111111111",
      "type": "FORM_TITLE",
      "groupUuid": "22222222-2222-2222-2222-222222222222",
      "groupType": "FORM_TITLE",
      "payload": {}
    },
    {
      "uuid": "33333333-3333-3333-3333-333333333333",
      "type": "INPUT_TEXT",
      "groupUuid": "44444444-4444-4444-4444-444444444444",
      "groupType": "INPUT_TEXT",
      "payload": {}
    }
  ],
  "settings": null
}

创建表单

POST /tally/forms
Content-Type: application/json

{
  "status": "DRAFT",
  "workspaceId": "3jW9Q1",
  "blocks": [
    {
      "type": "FORM_TITLE",
      "uuid": "11111111-1111-1111-1111-111111111111",
      "groupUuid": "22222222-2222-2222-2222-222222222222",
      "groupType": "FORM_TITLE",
      "title": "My Form",
      "payload": {}
    },
    {
      "type": "INPUT_TEXT",
      "uuid": "33333333-3333-3333-3333-333333333333",
      "groupUuid": "44444444-4444-4444-4444-444444444444",
      "groupType": "INPUT_TEXT",
      "title": "Your name",
      "payload": {}
    }
  ]
}

区块类型:

  • 表单标题- 表单标题区块
  • 输入_文本- 单行文本输入
  • 输入_邮箱- 邮箱输入
  • 输入_数字- 数字输入
  • 输入_电话号码- 电话号码输入
  • 输入_日期- 日期选择器
  • 输入_时间- 时间选择器
  • 输入_链接- 网址输入
  • 文本域- 多行文本输入
  • 多项选择- 单选按钮
  • 复选框- 复选框组
  • 下拉菜单- 下拉选择
  • 线性量表- 量表评分
  • 评分- 星级评分
  • 文件上传- 文件上传字段
  • 签名- 签名字段
  • 支付- 支付字段
  • 隐藏字段- 隐藏字段

注意:区块uuidgroupUuid必须是有效的UUID(GUID)。

更新表单

PATCH /tally/forms/{formId}
Content-Type: application/json

{
  "name": "Updated Form Name",
  "status": "PUBLISHED"
}

状态值:

  • 草稿- 表单为草稿状态
  • 已发布- 表单已上线

删除表单

DELETE /tally/forms/{formId}

将表单移至回收站。

表单问题

列出问题

GET /tally/forms/{formId}/questions

响应:

{
  "questions": [
    {
      "uuid": "33333333-3333-3333-3333-333333333333",
      "type": "INPUT_TEXT",
      "title": "Your name"
    }
  ],
  "hasResponses": true
}

表单提交

列出提交

GET /tally/forms/{formId}/submissions

查询参数:

  • 页码- 页码(默认值:1)
  • 限制- 每页项目数(默认值:50)
  • 开始日期- 按开始日期筛选(ISO 8601格式)
  • 结束日期- 按结束日期筛选(ISO 8601格式)
  • 后续ID- 获取此ID之后的提交(用于游标分页)

响应:

{
  "page": 1,
  "limit": 50,
  "hasMore": false,
  "totalNumberOfSubmissionsPerFilter": {
    "all": 42,
    "completed": 40,
    "partial": 2
  },
  "questions": [
    {
      "uuid": "33333333-3333-3333-3333-333333333333",
      "type": "INPUT_TEXT",
      "title": "Your name"
    }
  ],
  "submissions": [
    {
      "id": "sub123",
      "respondentId": "resp456",
      "formId": "GxdRaQ",
      "createdAt": "2026-02-09T10:00:00.000Z",
      "isCompleted": true,
      "responses": [
        {
          "questionId": "33333333-3333-3333-3333-333333333333",
          "value": "John Doe"
        }
      ]
    }
  ]
}

获取提交

GET /tally/forms/{formId}/submissions/{submissionId}

删除提交

DELETE /tally/forms/{formId}/submissions/{submissionId}

工作空间

列出工作空间

GET /tally/workspaces

响应:

{
  "items": [
    {
      "id": "3jW9Q1",
      "name": "My Workspace",
      "createdByUserId": "w2lBkb",
      "createdAt": "2026-02-09T08:35:53.000Z",
      "updatedAt": "2026-02-09T08:35:53.000Z"
    }
  ],
  "page": 1,
  "limit": 50,
  "total": 1,
  "hasMore": false
}

获取工作空间

GET /tally/workspaces/{workspaceId}

响应:

{
  "id": "3jW9Q1",
  "name": "My Workspace",
  "createdByUserId": "w2lBkb",
  "createdAt": "2026-02-09T08:35:53.000Z",
  "members": [
    {
      "id": "w2lBkb",
      "firstName": "John",
      "lastName": "Doe",
      "email": "john@example.com"
    }
  ]
}

创建工作空间

POST /tally/workspaces
Content-Type: application/json

{
  "name": "New Workspace"
}

注意:创建工作空间需要专业版订阅。

更新工作空间

PATCH /tally/workspaces/{workspaceId}
Content-Type: application/json

{
  "name": "Updated Workspace Name"
}

删除工作空间

DELETE /tally/workspaces/{workspaceId}

将工作空间及其所有表单移至回收站。

组织用户

列出用户

GET /tally/organizations/{organizationId}/users

响应:

[
  {
    "id": "w2lBkb",
    "firstName": "John",
    "lastName": "Doe",
    "email": "john@example.com",
    "createdAt": "2026-02-07T20:58:54.000Z"
  }
]

移除用户

DELETE /tally/organizations/{organizationId}/users/{userId}

组织邀请

列出邀请

GET /tally/organizations/{organizationId}/invites

创建邀请

POST /tally/organizations/{organizationId}/invites
Content-Type: application/json

{
  "email": "newuser@example.com",
  "workspaceIds": ["3jW9Q1"]
}

取消邀请

DELETE /tally/organizations/{organizationId}/invites/{inviteId}

Webhooks

列出Webhooks

GET /tally/webhooks

注意:列出Webhooks可能需要特定权限。

创建 Webhook

POST /tally/webhooks
Content-Type: application/json

{
  "formId": "GxdRaQ",
  "url": "https://your-endpoint.com/webhook",
  "eventTypes": ["FORM_RESPONSE"]
}

Webhook 事件类型:

  • 表单响应- 当提交新的表单响应时触发

更新 Webhook

PATCH /tally/webhooks/{webhookId}
Content-Type: application/json

{
  "url": "https://new-endpoint.com/webhook"
}

删除 Webhook

DELETE /tally/webhooks/{webhookId}

列出 Webhook 事件

GET /tally/webhooks/{webhookId}/events

重试 Webhook 事件

POST /tally/webhooks/{webhookId}/events/{eventId}

分页

Tally 使用基于页面的分页:

GET /tally/forms?page=1&limit=50

响应包含分页信息:

{
  "items": [...],
  "page": 1,
  "limit": 50,
  "total": 100,
  "hasMore": true
}

对于提交,也可以使用基于游标的分页,通过afterId参数实现。

代码示例

JavaScript

const response = await fetch(
  'https://gateway.maton.ai/tally/forms',
  {
    headers: {
      'Authorization': `Bearer ${process.env.MATON_API_KEY}`,
      'User-Agent': 'Maton/1.0'
    }
  }
);
const data = await response.json();
console.log(data.items);

Python

import os
import requests

response = requests.get(
    'https://gateway.maton.ai/tally/forms',
    headers={
        'Authorization': f'Bearer {os.environ["MATON_API_KEY"]}',
        'User-Agent': 'Maton/1.0'
    }
)
data = response.json()
print(data['items'])

创建表单并获取提交

import os
import requests
import uuid

headers = {
    'Authorization': f'Bearer {os.environ["MATON_API_KEY"]}',
    'User-Agent': 'Maton/1.0'
}

# Create a simple form
form_data = {
    'status': 'DRAFT',
    'blocks': [
        {
            'type': 'FORM_TITLE',
            'uuid': str(uuid.uuid4()),
            'groupUuid': str(uuid.uuid4()),
            'groupType': 'FORM_TITLE',
            'title': 'Contact Form',
            'payload': {}
        },
        {
            'type': 'INPUT_EMAIL',
            'uuid': str(uuid.uuid4()),
            'groupUuid': str(uuid.uuid4()),
            'groupType': 'INPUT_EMAIL',
            'title': 'Your email',
            'payload': {}
        }
    ]
}

response = requests.post(
    'https://gateway.maton.ai/tally/forms',
    headers=headers,
    json=form_data
)
form = response.json()
print(f"Created form: {form['id']}")

# Get submissions for a form
response = requests.get(
    f'https://gateway.maton.ai/tally/forms/{form["id"]}/submissions',
    headers=headers
)
submissions = response.json()
print(f"Total submissions: {submissions['totalNumberOfSubmissionsPerFilter']['all']}")

注意事项

  • 表单和工作区 ID 是简短的字母数字字符串(例如,GxdRaQ
  • 区块uuid并且groupUuid字段必须是有效的UUID(GUID)
  • 创建工作空间需要专业版订阅
  • API处于公开测试阶段,可能会发生变化
  • 频率限制:每分钟100个请求
  • 使用webhook而非轮询来获取实时提交通知
  • 重要提示:当通过管道将curl输出传递给jq或其他命令时,某些shell环境中像$MATON_API_KEY这样的环境变量可能无法正确展开

错误处理

状态码含义
400缺少Tally连接或验证错误
401无效或缺少Maton API密钥
403权限不足
404资源未找到
429请求频率受限 (100次/分钟)
4xx/5xx 错误来自 Tally API 的透传错误

故障排除:API 密钥问题

  1. 请检查MATON_API_KEY环境变量是否已设置:
echo $MATON_API_KEY
  1. 通过列出连接来验证 API 密钥是否有效:
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://ctrl.maton.ai/connections')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF

故障排除:无效的应用名称

  1. 请确保您的 URL 路径以tally开头。例如:
  • 正确示例:https://gateway.maton.ai/tally/forms
  • 错误示例:https://gateway.maton.ai/forms

资源

免责申明
部分文章来自各大搜索引擎,如有侵权,请与我联系删除。
打赏
文章底部电脑广告
手机广告位-内容正文底部

相关文章

您是本站第315015名访客 今日有452篇新文章/评论