home / skills / openclaw / skills / tally

tally skill

/skills/yujesyoga/tally

This skill creates and edits Tally forms programmatically via API, enabling rapid survey, feedback, and questionnaire automation.

npx playbooks add skill openclaw/skills --skill tally

Review the files below or copy the command above to add this skill to your agents.

Files (2)
SKILL.md
6.3 KB
---
name: tally
version: 1.0.0
description: Create and edit Tally forms via API. Use when building surveys, feedback forms, or questionnaires programmatically. Supports all question types including text inputs, multiple choice, checkboxes, ratings (via workaround), and more.
---

# Tally Forms API

Create and edit Tally.so forms programmatically via their REST API.

## Authentication

```bash
TALLY_KEY=$(cat ~/.config/tally/api_key)
```

## Endpoints

| Action | Method | Endpoint |
|--------|--------|----------|
| List forms | GET | `https://api.tally.so/forms` |
| Get form | GET | `https://api.tally.so/forms/{id}` |
| Update form | PATCH | `https://api.tally.so/forms/{id}` |
| Get submissions | GET | `https://api.tally.so/forms/{id}/submissions` |

## Block Structure

Tally forms are composed of **blocks**. Questions require **multiple blocks grouped by `groupUuid`**:

```json
{
  "uuid": "q1-title",
  "type": "TITLE",
  "groupUuid": "group-q1",
  "groupType": "QUESTION",
  "payload": {
    "safeHTMLSchema": [["Question text here", [["tag", "span"]]]]
  }
},
{
  "uuid": "q1-input",
  "type": "INPUT_TEXT",
  "groupUuid": "group-q1",
  "groupType": "QUESTION",
  "payload": {"isRequired": true}
}
```

**Key:** TITLE block + input block must share the same `groupUuid`.

## Block Types

### Structure
- `FORM_TITLE` - Form title and submit button
- `TEXT` - Paragraph text
- `HEADING_1`, `HEADING_2`, `HEADING_3` - Section headers
- `TITLE` - Question label (inside QUESTION group)
- `DIVIDER` - Separator line

### Inputs
- `INPUT_TEXT` - Short text
- `INPUT_NUMBER` - Number
- `INPUT_EMAIL` - Email
- `INPUT_DATE` - Date picker
- `INPUT_PHONE_NUMBER` - Phone
- `TEXTAREA` - Long text

### Selection
- `MULTIPLE_CHOICE_OPTION` - Single select (groupType: MULTIPLE_CHOICE)
- `CHECKBOX` - Multi select (groupType: CHECKBOXES)
- `DROPDOWN_OPTION` - Dropdown option

### ⚠️ Types that don't render well via API
- `RATING` - Stars don't display
- `LINEAR_SCALE` - Scale doesn't display

**Workaround:** Use `MULTIPLE_CHOICE_OPTION` with star emojis.

## Examples

### Form title
```json
{
  "uuid": "title-001",
  "type": "FORM_TITLE",
  "groupUuid": "group-title",
  "groupType": "FORM_TITLE",
  "payload": {
    "title": "My Survey",
    "button": {"label": "Submit"}
  }
}
```

### Section header
```json
{
  "uuid": "sec1-head",
  "type": "HEADING_2",
  "groupUuid": "group-sec1",
  "groupType": "TEXT",
  "payload": {
    "safeHTMLSchema": [["📊 Section Title", [["tag", "span"]]]]
  }
}
```

### Text input question
```json
{
  "uuid": "q1-title",
  "type": "TITLE",
  "groupUuid": "group-q1",
  "groupType": "QUESTION",
  "payload": {
    "safeHTMLSchema": [["What is your name?", [["tag", "span"]]]]
  }
},
{
  "uuid": "q1-input",
  "type": "INPUT_TEXT",
  "groupUuid": "group-q1",
  "groupType": "QUESTION",
  "payload": {"isRequired": true}
}
```

### Multiple choice (single answer)
```json
{
  "uuid": "q2-title",
  "type": "TITLE",
  "groupUuid": "group-q2",
  "groupType": "QUESTION",
  "payload": {
    "safeHTMLSchema": [["How did you hear about us?", [["tag", "span"]]]]
  }
},
{
  "uuid": "q2-opt1",
  "type": "MULTIPLE_CHOICE_OPTION",
  "groupUuid": "group-q2",
  "groupType": "MULTIPLE_CHOICE",
  "payload": {"isRequired": true, "index": 0, "isFirst": true, "isLast": false, "text": "Social media"}
},
{
  "uuid": "q2-opt2",
  "type": "MULTIPLE_CHOICE_OPTION",
  "groupUuid": "group-q2",
  "groupType": "MULTIPLE_CHOICE",
  "payload": {"isRequired": true, "index": 1, "isFirst": false, "isLast": true, "text": "Friend referral"}
}
```

### Checkboxes (multiple answers)
```json
{
  "uuid": "q3-title",
  "type": "TITLE",
  "groupUuid": "group-q3",
  "groupType": "QUESTION",
  "payload": {
    "safeHTMLSchema": [["What features interest you?", [["tag", "span"]]]]
  }
},
{
  "uuid": "q3-cb1",
  "type": "CHECKBOX",
  "groupUuid": "group-q3",
  "groupType": "CHECKBOXES",
  "payload": {"index": 0, "isFirst": true, "isLast": false, "text": "Feature A"}
},
{
  "uuid": "q3-cb2",
  "type": "CHECKBOX",
  "groupUuid": "group-q3",
  "groupType": "CHECKBOXES",
  "payload": {"index": 1, "isFirst": false, "isLast": true, "text": "Feature B"}
}
```

### Rating scale (workaround with stars)
```json
{
  "uuid": "q4-title",
  "type": "TITLE",
  "groupUuid": "group-q4",
  "groupType": "QUESTION",
  "payload": {
    "safeHTMLSchema": [["How would you rate our service?", [["tag", "span"]]]]
  }
},
{
  "uuid": "q4-opt1",
  "type": "MULTIPLE_CHOICE_OPTION",
  "groupUuid": "group-q4",
  "groupType": "MULTIPLE_CHOICE",
  "payload": {"isRequired": true, "index": 0, "isFirst": true, "isLast": false, "text": "⭐ Poor"}
},
{
  "uuid": "q4-opt2",
  "type": "MULTIPLE_CHOICE_OPTION",
  "groupUuid": "group-q4",
  "groupType": "MULTIPLE_CHOICE",
  "payload": {"isRequired": true, "index": 1, "isFirst": false, "isLast": false, "text": "⭐⭐ Fair"}
},
{
  "uuid": "q4-opt3",
  "type": "MULTIPLE_CHOICE_OPTION",
  "groupUuid": "group-q4",
  "groupType": "MULTIPLE_CHOICE",
  "payload": {"isRequired": true, "index": 2, "isFirst": false, "isLast": false, "text": "⭐⭐⭐ Good"}
},
{
  "uuid": "q4-opt4",
  "type": "MULTIPLE_CHOICE_OPTION",
  "groupUuid": "group-q4",
  "groupType": "MULTIPLE_CHOICE",
  "payload": {"isRequired": true, "index": 3, "isFirst": false, "isLast": false, "text": "⭐⭐⭐⭐ Very good"}
},
{
  "uuid": "q4-opt5",
  "type": "MULTIPLE_CHOICE_OPTION",
  "groupUuid": "group-q4",
  "groupType": "MULTIPLE_CHOICE",
  "payload": {"isRequired": true, "index": 4, "isFirst": false, "isLast": true, "text": "⭐⭐⭐⭐⭐ Excellent"}
}
```

## Update Command

```bash
TALLY_KEY=$(cat ~/.config/tally/api_key)

# Backup first
curl -s "https://api.tally.so/forms/{ID}" \
  -H "Authorization: Bearer $TALLY_KEY" > /tmp/backup.json

# Update
curl -s "https://api.tally.so/forms/{ID}" \
  -X PATCH \
  -H "Authorization: Bearer $TALLY_KEY" \
  -H "Content-Type: application/json" \
  -d @/tmp/form.json

# Verify
curl -s "https://api.tally.so/forms/{ID}" \
  -H "Authorization: Bearer $TALLY_KEY" | jq '.blocks | length'
```

## Best Practices

1. **Always backup** before modifying a form
2. **Use descriptive UUIDs** (q1-title, q1-input, sec1-head)
3. **Section titles:** Use lowercase with emoji prefix (📊 General feedback)
4. **For ratings:** Use MULTIPLE_CHOICE with ⭐ emojis instead of RATING type
5. **Verify after update:** Check block count matches expected

Overview

This skill enables creating and editing Tally.so forms programmatically via the Tally REST API. It provides concrete patterns for building form blocks, grouping question elements with groupUuid, and performing safe updates and backups. Use it when you need to generate surveys, feedback forms, or questionnaires from code.

How this skill works

The skill talks to Tally endpoints to list forms, fetch a form, update a form, and retrieve submissions. Forms are assembled from blocks; every question is a group of blocks that share the same groupUuid (a TITLE block plus one or more input or option blocks). Updates are done by PATCHing the form blocks, and recommended workflows include backing up the form JSON before applying changes.

When to use it

  • Automate creation of surveys, lead capture forms, or onboarding questionnaires
  • Generate or modify forms from backend scripts or CI jobs
  • Bulk-edit many forms with consistent structure or branding
  • Export/backup form definitions before mass changes
  • Programmatically add rating-like questions using emoji workarounds

Best practices

  • Always fetch and save a backup of the form JSON before making edits
  • Use descriptive, stable UUIDs (e.g., q1-title, q1-input, sec1-head) so diffs are readable
  • Group question elements with the same groupUuid: TITLE + input/option blocks
  • Prefer MULTIPLE_CHOICE_OPTION with star emojis for ratings, since RATING and LINEAR_SCALE don’t render reliably via API
  • After an update, verify block count and key fields to confirm the form applied correctly

Example use cases

  • Create a 10-question customer satisfaction survey from a template and deploy it via CI
  • Programmatically add a new consent checkbox to dozens of forms before a policy change
  • Build a feedback form that includes sections and conditional blocks generated from a data model
  • Replace a visual RATING question with a MULTIPLE_CHOICE workaround using star emojis
  • Backup all form definitions to a JSON archive before a major restructure

FAQ

Which API endpoints do I need?

Use GET /forms to list, GET /forms/{id} to fetch, PATCH /forms/{id} to update, and GET /forms/{id}/submissions to retrieve responses.

How do I build a question via the API?

Create a TITLE block with a groupUuid, then add an input or option block that shares the same groupUuid and groupType (e.g., QUESTION + INPUT_TEXT or MULTIPLE_CHOICE).

Can I use the RATING block type?

Rating and linear scale types often don’t render via the API. Use MULTIPLE_CHOICE_OPTION items with star emojis as a reliable workaround.

Any safety tips for updates?

Always backup the current form JSON, perform the PATCH, then verify the block count and key block properties to ensure the change applied correctly.