# API keys
Source: https://developers.tally.so/api-reference/api-keys
Learn how API keys work on Tally
API keys on Tally allow you to access your account programmatically. This is useful for integrating Tally into your application or with other tools and services.
For now, each API key is tied to a specific user - meaning that it will inherit the permissions of
the user, also when they change. With the key you will be able to access all of the user's
resources.
## Creating an API key
You can create an API key by following these steps:
Go to **Settings** > [**API keys**](https://tally.so/settings/api-keys).
Click on the "Create API key" button.
Currently, you can only create an API key in the context of your own user. While we might add fine-grained permissions in the future, it's not option right now.
Once your API key is created, make sure to copy and store it in a safe place. You won't be able to see it again for security reasons. If it gets lost, you can create a new one.
Now that you have your API key, you can use it to access your account's resources programmatically via any API request as a bearer token.
```
Authorization: Bearer tly-xxxx
```
When you remove a user from your organization (or they leave your organization), all API keys
associated with that user will stop working as well. Keep this in mind when managing users.
# Changelog
Source: https://developers.tally.so/api-reference/changelog
Changes made to the Tally API worth knowing about
We try to version the API using dates to maintain a highly backwards compatible API. You can
specify a version using the `tally-version` header, e.g. `tally-version: 2025-02-01`.
#### Breaking changes
* `POST /forms` and `PATCH /forms/{formId}` no longer accept `DELETED` as a `status`. Requests using it will be rejected with a `400` error. Previously the form was marked as deleted without being moved to the trash, leaving it unrecoverable. Use `DELETE /forms/{formId}` to delete a form.
#### New endpoints
* `GET /workspaces/{workspaceId}/folders`
List a workspace's folders
* `POST /workspaces/{workspaceId}/folders`
Create a folder
* `PATCH /workspaces/{workspaceId}/folders/{id}`
Rename a folder
* `DELETE /workspaces/{workspaceId}/folders/{id}`
Delete a folder and its subfolders, moving any forms they contain to trash
#### Changed endpoints
* `GET /workspaces`
Each workspace now includes a `folders` array
* `GET /workspaces/{workspaceId}`
The response now includes a `folders` array
#### New endpoints
* `GET /forms/{formId}/analytics/metrics`
Get aggregate form metrics
* `GET /forms/{formId}/analytics/visits`
Get form visits over time
* `GET /forms/{formId}/analytics/submissions`
Get completed and partial submissions over time
* `GET /forms/{formId}/analytics/dimensions`
Get visitor breakdowns by source, browser, OS, device and location
* `GET /forms/{formId}/analytics/drop-off`
Get per-question drop-off statistics
#### Changed endpoints
* `POST /forms`
Form settings accept rich text (`html` with `mentions`) for email and redirect fields
* `GET /forms/{formId}`
Form settings now return rich text (`html` with `mentions`) for email and redirect fields
* `PATCH /forms/{formId}`
Form settings accept rich text (`html` with `mentions`) for email and redirect fields
#### Changed endpoints
* `GET /forms/{formId}/submissions`
Each submission now includes `previewUrl` and `pdfUrl`
* `GET /forms/{formId}/submissions/{submissionId}`
The response now includes `previewUrl` and `pdfUrl`
#### Changed endpoints
* `GET /forms/{formId}/questions`
Field references (used for default answers and mentions) can now resolve to utility fields, such
as `utility::today()`
#### Breaking changes
* Block payloads are now validated against the schema. Requests with invalid block payload structures will be rejected with a `400` error. Previously, malformed block payloads were accepted silently.
#### New endpoints
* `GET /forms/{formId}/questions`
Get form questions
* `GET /forms/{formId}/submissions/{submissionId}`
Get a specific form submission
* `GET /organizations/{organizationId}/users`
View organization users
* `DELETE /organizations/{organizationId}/users/{userId}`
Remove users from organization
* `GET /organizations/{organizationId}/invites`
View pending invites
* `POST /organizations/{organizationId}/invites`
Invite users to organization
* `DELETE /organizations/{organizationId}/invites/{inviteId}`
Cancel pending invites
* `GET /webhooks`
List configured webhooks
* `GET /webhooks/{webhookId}/events`
List webhook events
* `POST /webhooks/{webhookId}/events/{eventId}`
Retry webhook events
#### Changed endpoints
* `GET /forms/{formId}/submissions`
Added new filtering options: `startDate`, `endDate` & `afterId`
#### New endpoints
* `GET /users/me`
#### Changed endpoints
* `GET /forms`
Now returns a paginated response instead of a flat list.
* `GET /workspaces`
Now returns a paginated response instead of a flat list.
#### Deprecated endpoints
* `GET /me`
Hello world! 🎉
# Dimensions
Source: https://developers.tally.so/api-reference/endpoint/forms/analytics/dimensions
GET /forms/{formId}/analytics/dimensions
Returns visitor breakdowns by source, browser, OS, device, and location.
# Drop-off
Source: https://developers.tally.so/api-reference/endpoint/forms/analytics/drop-off
GET /forms/{formId}/analytics/drop-off
Returns per-question drop-off statistics for a form.
# Metrics
Source: https://developers.tally.so/api-reference/endpoint/forms/analytics/metrics
GET /forms/{formId}/analytics/metrics
Returns aggregate metrics for a form (visits, submissions, completion rate, and more).
# Submissions
Source: https://developers.tally.so/api-reference/endpoint/forms/analytics/submissions
GET /forms/{formId}/analytics/submissions
Returns completed and partial submission counts for a form over time.
# Visits
Source: https://developers.tally.so/api-reference/endpoint/forms/analytics/visits
GET /forms/{formId}/analytics/visits
Returns visit counts for a form over time.
# Deleting forms
Source: https://developers.tally.so/api-reference/endpoint/forms/delete
DELETE /forms/{formId}
Deletes a form by its ID and moves it to the trash.
# Fetching forms
Source: https://developers.tally.so/api-reference/endpoint/forms/get
GET /forms/{formId}
Returns a single form by its ID with all its blocks and settings.
# Listing forms
Source: https://developers.tally.so/api-reference/endpoint/forms/list
GET /forms
Returns a paginated array of form objects.
# Updating forms
Source: https://developers.tally.so/api-reference/endpoint/forms/patch
PATCH /forms/{formId}
Updates a form's settings, blocks, or status.
# Creating forms
Source: https://developers.tally.so/api-reference/endpoint/forms/post
POST /forms
Creates a new form, optionally based on a template or within a specific workspace.
# Listing questions
Source: https://developers.tally.so/api-reference/endpoint/forms/questions/list
GET /forms/{formId}/questions
Returns a list of all questions in a form.
# Deleting submissions
Source: https://developers.tally.so/api-reference/endpoint/forms/submissions/delete
DELETE /forms/{formId}/submissions/{submissionId}
Deletes a specific submission from a form.
# Fetching submissions
Source: https://developers.tally.so/api-reference/endpoint/forms/submissions/get
GET /forms/{formId}/submissions/{submissionId}
Returns a specific form submission with all its responses and the form questions.
# Listing submissions
Source: https://developers.tally.so/api-reference/endpoint/forms/submissions/list
GET /forms/{formId}/submissions
Returns a paginated list of form submissions with their responses.
Looking for real-time submissions? The most efficient way to instantly retrieve new
submissions is by using a [webhook](https://tally.so/help/webhooks). This allows you to receive
data as soon as a form is submitted, without needing to poll the API.
# Cancelling invites
Source: https://developers.tally.so/api-reference/endpoint/organizations/invites/delete
DELETE /organizations/{organizationId}/invites/{inviteId}
Cancels a pending invitation to join workspaces within your organization. Only the user who created the invite can cancel it.
# Listing invites
Source: https://developers.tally.so/api-reference/endpoint/organizations/invites/get
GET /organizations/{organizationId}/invites
Returns a list of all invites in your organization.
# Creating invites
Source: https://developers.tally.so/api-reference/endpoint/organizations/invites/post
POST /organizations/{organizationId}/invites
Invites users to join specific workspaces within your organization.
# Removing users
Source: https://developers.tally.so/api-reference/endpoint/organizations/users/delete
DELETE /organizations/{organizationId}/users/{userId}
Removes a user from your organization. Only the organization creator can remove other members, or users can remove themselves.
# Listing users
Source: https://developers.tally.so/api-reference/endpoint/organizations/users/get
GET /organizations/{organizationId}/users
Returns a list of all users in your organization.
# Fetching user info
Source: https://developers.tally.so/api-reference/endpoint/users/me/get
GET /users/me
Returns information about the current authenticated user.
# Deleting webhooks
Source: https://developers.tally.so/api-reference/endpoint/webhooks/delete
DELETE /webhooks/{webhookId}
Deletes a webhook. If this is the last webhook for a form, the webhooks integration will also be marked as deleted.
# Listing webhook events
Source: https://developers.tally.so/api-reference/endpoint/webhooks/events/get
GET /webhooks/{webhookId}/events
Returns a paginated list of webhook delivery events for a specific webhook, including delivery status, response codes, and retry information.
# Retrying webhook events
Source: https://developers.tally.so/api-reference/endpoint/webhooks/events/retry
POST /webhooks/{webhookId}/events/{eventId}
Retries sending a failed webhook event. This will attempt to deliver the webhook payload again to the configured endpoint.
Failed webhook events are automatically retried up to 5 times with exponential backoff intervals
(5 minutes, 30 minutes, 1 hour, 6 hours, 24 hours) before being permanently dropped.
# Listing webhooks
Source: https://developers.tally.so/api-reference/endpoint/webhooks/get
GET /webhooks
Returns a paginated list of all webhooks across your accessible forms and workspaces.
# Updating webhooks
Source: https://developers.tally.so/api-reference/endpoint/webhooks/patch
PATCH /webhooks/{webhookId}
Updates an existing webhook configuration.
# Creating webhooks
Source: https://developers.tally.so/api-reference/endpoint/webhooks/post
POST /webhooks
Creates a new webhook for a form to receive form events.
# Deleting workspaces
Source: https://developers.tally.so/api-reference/endpoint/workspaces/delete
DELETE /workspaces/{workspaceId}
Deletes a workspace and all its associated forms. The workspace and forms are moved to trash and can be restored later. Forms in DRAFT or PUBLISHED state will be marked as DELETED.
# Deleting folders
Source: https://developers.tally.so/api-reference/endpoint/workspaces/folders/delete
DELETE /workspaces/{workspaceId}/folders/{id}
Deletes a folder and its entire subtree by its ID, moving any contained forms to trash. Requires a Pro subscription.
# Listing folders
Source: https://developers.tally.so/api-reference/endpoint/workspaces/folders/list
GET /workspaces/{workspaceId}/folders
Returns the folders in a workspace. Requires a Pro subscription.
Folders are also included inline on each workspace in the
[workspace list response](/api-reference/endpoint/workspaces/list), under the
`folders` array.
# Updating folders
Source: https://developers.tally.so/api-reference/endpoint/workspaces/folders/patch
PATCH /workspaces/{workspaceId}/folders/{id}
Renames a folder by its ID. Requires a Pro subscription.
# Creating folders
Source: https://developers.tally.so/api-reference/endpoint/workspaces/folders/post
POST /workspaces/{workspaceId}/folders
Creates a folder in a workspace. Pass parentId to nest it inside another folder. Requires a Pro subscription.
# Fetching workspaces
Source: https://developers.tally.so/api-reference/endpoint/workspaces/get
GET /workspaces/{workspaceId}
Returns a single workspace by its ID with associated members.
# Listing workspaces
Source: https://developers.tally.so/api-reference/endpoint/workspaces/list
GET /workspaces
Returns a paginated array of workspace objects with associated users and pending invites.
# Updating workspaces
Source: https://developers.tally.so/api-reference/endpoint/workspaces/patch
PATCH /workspaces/{workspaceId}
Updates a workspace's information by its ID.
# Creating workspaces
Source: https://developers.tally.so/api-reference/endpoint/workspaces/post
POST /workspaces
Creates a new workspace and assigns the authenticated user as a member. Requires a Pro subscription.
# Introduction
Source: https://developers.tally.so/api-reference/introduction
Fundamental concepts of Tally's API.
## Base URL
The Tally API follows REST principles and is accessible only via HTTPS. For security reasons, unencrypted HTTP requests are not allowed. The Base URL for all API endpoints is:
```bash Terminal theme={null}
https://api.tally.so
```
## Authentication
Authentication to the Tally API requires an Authorization header with a Bearer token. Include the Authorization header in your requests as shown below:
```bash Terminal theme={null}
Authorization: Bearer
```
Learn more about [how to get your API key](/api-reference/api-keys).
## Response codes
The API returns standard HTTP response codes to indicate the success or failure of an API request. Here are a few examples:
| Code | Description |
| ----- | ----------------------------------------------------------------------- |
| `200` | Success - The request completed successfully |
| `400` | Bad Request - The request was malformed or contained invalid parameters |
| `401` | Unauthorized - Authentication credentials are missing or invalid |
| `403` | Forbidden - You don't have permission to access this resource |
| `404` | Not Found - The requested resource doesn't exist |
| `429` | Rate Limited - You've exceeded the allowed number of requests |
| `500` | Server Error - Something went wrong on our end |
## Rate Limits
To ensure fair usage and maintain service quality, the Tally API limits requests to 100 per minute.
Avoid rate limits with webhooks! Instead of polling for new form submissions, use
[webhooks](https://tally.so/help/webhooks) to receive data instantly when forms are submitted.
This is more efficient and won't count against your rate limit.
# MCP server
Source: https://developers.tally.so/api-reference/mcp
Build Tally forms and list forms or submissions using AI assistants via the Model Context Protocol
The Tally MCP server is currently in beta and subject to change.
## What is MCP?
The Model Context Protocol (MCP) lets you build Tally forms and retrieve forms or submissions
using natural language through AI assistants like Claude.
## Server URL
The Tally MCP server is available at:
```bash theme={null}
https://api.tally.so/mcp
```
## Authentication
The Tally MCP server supports two authentication methods:
### Option 1: OAuth (Recommended)
The easiest way to connect is through OAuth. Many AI assistants support OAuth authentication for MCP servers, allowing you to connect with just a few clicks without manually managing API keys.
When your AI assistant prompts for OAuth authentication:
1. Click the connect button or authorization link
2. Log in to your Tally account (if not already logged in)
3. Authorize the connection
4. The AI assistant will automatically configure the connection
### Option 2: API Key
You can also authenticate using an API key in the Authorization header:
```bash theme={null}
Authorization: Bearer tly-xxxx
```
Learn more about [how to get your API key](/api-reference/api-keys).
## Configuration
### Claude Desktop
This method works for Claude Desktop and [claude.ai](https://claude.ai), and applies across all Claude apps that support connectors, including Claude Chat, Claude Code, and Claude Cowork.
1. Open Claude Desktop (or [claude.ai](https://claude.ai) in your browser) and navigate to **Customize > Connectors > Add custom connector** from the sidebar on the left.
2. Give the connector a name and the Tally MCP server URL.
```bash theme={null}
https://api.tally.so/mcp
```
3. Click "Add" to save the connector.
4. Restart Claude Desktop
5. The first time you use the Tally MCP server, Claude will open an OAuth flow to authenticate with your Tally account.
### Claude Code CLI
To connect Claude Code to the Tally MCP server, run the following command in your terminal:
```bash theme={null}
claude mcp add tally --transport http https://api.tally.so/mcp
```
Claude Code will handle the OAuth flow automatically when you first use the Tally MCP server. You can verify the connection by running the `/mcp` command inside Claude Code.
### Cursor
1. Open **Cursor Settings > Tools & MCP**
2. Click **New MCP Server**
3. Paste the following JSON to configure the Tally MCP server:
```json theme={null}
{
"mcpServers": {
"tally": {
"url": "https://api.tally.so/mcp",
"headers": {
"Authorization": "Bearer YOUR_API_KEY_HERE"
}
}
}
}
```
## Example Usage
Once configured, you can ask your AI assistant to create forms using natural language. Here are some examples:
### Creating a Simple Contact Form
```
Create a simple contact form
```
The AI assistant will automatically create a contact form with commonly expected fields based on its understanding of what a typical contact form should include.
### Updating the Contact Form
If the generated form isn't exactly what you wanted, you can easily modify it by following up:
```
We don't need the Company field, remove the consent checkbox and maybe add a captcha
```
The AI assisant should correctly modify the form and save it.
### Creating a form with specific fields
Alternatively, you can be explicit about exactly what fields you want:
```
Create a contact form with these specific fields:
- Name (required)
- Email (required)
- Phone (optional)
- Message (required)
- Captcha (required)
```
The AI assistant should create a form with the specified fields and save it.
### Updating an existing form
```
Update this form https://tally.so/r/a1B2c3
- Remove the phone number field
- Also add a captcha
- Make company field optional
```
The AI assistant will use the MCP tools to load your form, make the requested changes, and save the updated version.
### Fetching form submissions
You can fetch submissions for any form, with optional filters for status and date range:
```
Show me all completed submissions for https://tally.so/r/a1B2c3 from January 2025
```
The AI assistant will fetch and display the matching submissions for your form, including question labels and response data.
### Listing forms
You can list forms across your accessible workspaces and ask for filtering by name, status, or recency:
```
Show my 10 most recently updated published forms
```
The AI assistant will call the MCP list forms tool and return matching forms with key details such as form name, URL, status, and last updated date.
## Example usage with Claude
## Configuring the Tally MCP server using OAuth with Claude
# Versioning
Source: https://developers.tally.so/api-reference/versioning
Learn how versioning works in the Tally API
Inspired by Stripe's versioning strategy, we try to version the API using dates to maintain a highly backwards compatible API.
When creating your API key, it will be tied by default to the latest version of the API and can not be changed. The version will be viewable from the [API keys dashboard](https://tally.so/settings/api-keys). You can however also manually specify a version to use at request level by providing the `tally-version` header.
If we would be introducing impossible to avoid breaking changes, you will be informed about this.
## Example
If you created an API key when we initially launched the Tally API, then your key is tied to version `2025-01-15`. If you would be fetching forms without providing the `tally-version` header, you would be fetching forms from the `2025-01-15` version of the API.
### Request
```bash theme={null}
curl -X GET 'https://api.tally.so/forms' \
-H 'Authorization: Bearer ' \
-H 'Content-Type: application/json'
```
### Response
```json theme={null}
[
{
"id": "LmBenY",
"name": "Test",
"isNameModifiedByUser": false,
"workspaceId": "kwob3J",
"organizationId": "kwob3J",
"status": "PUBLISHED",
"hasDraftBlocks": false,
"numberOfSubmissions": 0,
"createdAt": "2025-01-28T09:23:24.000Z",
"updatedAt": "2025-01-28T09:41:22.000Z",
"index": 0,
"isClosed": false
},
{
"id": "qnGe3Z",
"name": "Contact form",
"isNameModifiedByUser": false,
"workspaceId": "kwob3J",
"organizationId": "kwob3J",
"status": "PUBLISHED",
"hasDraftBlocks": false,
"numberOfSubmissions": 7,
"createdAt": "2025-01-14T09:55:31.000Z",
"updatedAt": "2025-01-23T13:09:13.000Z",
"index": 1,
"isClosed": false
}
]
```
Then in version `2025-02-01`, we introduced some breaking changes to the `/forms` endpoint and introduced pagination meta data while the data is wrapped within the `items` key.
To make use of this you can explicitly specify the version using the `tally-version` header.
### Request
```bash theme={null}
curl -X GET 'https://api.tally.so/forms' \
-H 'Authorization: Bearer ' \
-H 'Content-Type: application/json' \
-H 'tally-version: 2025-02-01'
```
### Response
```json theme={null}
{
"items": [
{
"id": "LmBenY",
"name": "Test",
"isNameModifiedByUser": false,
"workspaceId": "kwob3J",
"organizationId": "kwob3J",
"status": "PUBLISHED",
"hasDraftBlocks": false,
"numberOfSubmissions": 0,
"createdAt": "2025-01-28T09:23:24.000Z",
"updatedAt": "2025-01-28T09:41:22.000Z",
"index": 0,
"isClosed": false
},
{
"id": "qnGe3Z",
"name": "Contact form",
"isNameModifiedByUser": false,
"workspaceId": "kwob3J",
"organizationId": "kwob3J",
"status": "PUBLISHED",
"hasDraftBlocks": false,
"numberOfSubmissions": 7,
"createdAt": "2025-01-14T09:55:31.000Z",
"updatedAt": "2025-01-23T13:09:13.000Z",
"index": 1,
"isClosed": false
}
],
"page": 1,
"limit": 50,
"total": 2,
"hasMore": false
}
```
You could also just rotate your API key to make use of the latest version by default.
# Calculated fields
Source: https://developers.tally.so/blocks-reference/calculated-fields
Learn how to use calculated fields in your forms in our [Help Center
guide](https://tally.so/help/form-calculator).
# Captcha
Source: https://developers.tally.so/blocks-reference/captcha
# Checkbox
Source: https://developers.tally.so/blocks-reference/checkbox
# Conditional logic
Source: https://developers.tally.so/blocks-reference/conditional-logic
Learn how to use conditional logic in your forms in our [Help Center
guide](https://tally.so/help/conditional-form-logic).
# Divider
Source: https://developers.tally.so/blocks-reference/divider
# Dropdown option
Source: https://developers.tally.so/blocks-reference/dropdown-option
# Embed
Source: https://developers.tally.so/blocks-reference/embed
# Embed audio
Source: https://developers.tally.so/blocks-reference/embed-audio
# Embed video
Source: https://developers.tally.so/blocks-reference/embed-video
# File upload
Source: https://developers.tally.so/blocks-reference/file-upload
# Form title
Source: https://developers.tally.so/blocks-reference/form-title
# Heading 1
Source: https://developers.tally.so/blocks-reference/heading1
# Heading 2
Source: https://developers.tally.so/blocks-reference/heading2
# Heading 3
Source: https://developers.tally.so/blocks-reference/heading3
# Hidden fields
Source: https://developers.tally.so/blocks-reference/hidden-fields
# Image
Source: https://developers.tally.so/blocks-reference/image
# Input date
Source: https://developers.tally.so/blocks-reference/input-date
Learn how to use the date block in your forms in our [Help Center
guide](https://tally.so/help/date).
# Input email
Source: https://developers.tally.so/blocks-reference/input-email
# Input link
Source: https://developers.tally.so/blocks-reference/input-link
# Input number
Source: https://developers.tally.so/blocks-reference/input-number
# Input phone number
Source: https://developers.tally.so/blocks-reference/input-phone-number
# Input text
Source: https://developers.tally.so/blocks-reference/input-text
# Input time
Source: https://developers.tally.so/blocks-reference/input-time
# Label
Source: https://developers.tally.so/blocks-reference/label
# Linear scale
Source: https://developers.tally.so/blocks-reference/linear-scale
# Matrix
Source: https://developers.tally.so/blocks-reference/matrix
# Matrix column
Source: https://developers.tally.so/blocks-reference/matrix-column
# Matrix row
Source: https://developers.tally.so/blocks-reference/matrix-row
# Multi select option
Source: https://developers.tally.so/blocks-reference/multi-select-option
# Multiple choice option
Source: https://developers.tally.so/blocks-reference/multiple-choice-option
# Page break
Source: https://developers.tally.so/blocks-reference/page-break
# Payment
Source: https://developers.tally.so/blocks-reference/payment
# Ranking option
Source: https://developers.tally.so/blocks-reference/ranking-option
# Rating
Source: https://developers.tally.so/blocks-reference/rating
# Respondent country
Source: https://developers.tally.so/blocks-reference/respondent-country
# Signature
Source: https://developers.tally.so/blocks-reference/signature
# Text
Source: https://developers.tally.so/blocks-reference/text
# Textarea
Source: https://developers.tally.so/blocks-reference/textarea
# Title
Source: https://developers.tally.so/blocks-reference/title
# Adding blocks to a form
Source: https://developers.tally.so/documentation/adding-blocks-to-a-form
Add new blocks to an existing form using the Tally API
## Prerequisites
* A Tally account
* An API key
* An existing form
## Request
To add blocks to an existing form, send a PATCH request to the `/forms/:id` endpoint with the blocks you want it to contain:
```bash theme={null}
curl -X PATCH 'https://api.tally.so/forms/:id' \
-H 'Authorization: Bearer ' \
-H 'Content-Type: application/json' \
-d '{
"name": "Test",
"status": "PUBLISHED",
"blocks": [
{
"uuid": "6ef8675d-33cb-419b-a81e-93982e726f2e",
"type": "FORM_TITLE",
"groupUuid": "073c835f-7ad4-459c-866d-4108b6b7e2e1",
"groupType": "TEXT",
"payload": {
"html": "Test",
"title": "Test"
}
},
{
"uuid": "48b4cdf3-2c9d-47d3-b8fb-b0ccabc5cd84",
"type": "TITLE",
"groupUuid": "93034250-5f05-4710-b8e0-5c9145c5b9ea",
"groupType": "QUESTION",
"payload": {
"html": "What'\''s your name?"
}
},
{
"uuid": "884ff838-97f9-4ac9-8db1-31aa052df988",
"type": "INPUT_TEXT",
"groupUuid": "3287d15c-c2b2-4f84-a915-bc57380a4b51",
"groupType": "INPUT_TEXT",
"payload": {
"isRequired": true,
"placeholder": ""
}
}
]
}'
```
This example adds two blocks to the form:
1. A title block with the text "What's your name?"
2. A required text input block
As you can see, the payload contains 3 blocks, while we only wanted to add 2. That is because you
always need to include all blocks when updating a form.
## Response
The API will respond with a 200 status code and with some form meta data:
```json theme={null}
{
"id": "m2fK5R",
"name": "Test",
"workspaceId": "kb3o5R",
"organizationId": "atL65s",
"status": "PUBLISHED",
"hasDraftBlocks": false,
"isClosed": false,
"updatedAt": "2024-12-20T10:34:19.262Z",
"createdAt": "2024-12-20T10:34:19.262Z"
}
```
Your form should now contain the updated blocks.
# Creating a contact form
Source: https://developers.tally.so/documentation/creating-a-contact-form
Learn how to create a contact form using the Tally API
## Prerequisites
* A Tally account
* An API key
## Request
To create the form, send a POST request to the `/forms` endpoint with the following payload:
```bash theme={null}
curl -X POST 'https://api.tally.so/forms' \
-H 'Authorization: Bearer ' \
-H 'Content-Type: application/json' \
-d '{
"status": "PUBLISHED",
"blocks": [
{
"uuid": "6ef8675d-33cb-419b-a81e-93982e726f2e",
"type": "FORM_TITLE",
"groupUuid": "073c835f-7ad4-459c-866d-4108b6b7e2e1",
"groupType": "TEXT",
"payload": {
"html": "Contact form"
}
},
{
"uuid": "48b4cdf3-2c9d-47d3-b8fb-b0ccabc5cd84",
"type": "TITLE",
"groupUuid": "93034250-5f05-4710-b8e0-5c9145c5b9ea",
"groupType": "QUESTION",
"payload": {
"html": "Name"
}
},
{
"uuid": "884ff838-97f9-4ac9-8db1-31aa052df988",
"type": "INPUT_TEXT",
"groupUuid": "3287d15c-c2b2-4f84-a915-bc57380a4b51",
"groupType": "INPUT_TEXT",
"payload": {
"isRequired": true,
"placeholder": "Enter your name"
}
},
{
"uuid": "7d9c2e31-b5aa-4c8b-9c2d-123456789abc",
"type": "TITLE",
"groupUuid": "456789ab-cdef-4321-b8e0-987654321def",
"groupType": "QUESTION",
"payload": {
"html": "Email"
}
},
{
"uuid": "9b3f5d2a-1c8e-4f7d-b6a9-def012345678",
"type": "INPUT_EMAIL",
"groupUuid": "5f6a7b8c-9d0e-4f12-a345-6789abcdef01",
"groupType": "INPUT_EMAIL",
"payload": {
"isRequired": true,
"placeholder": "Enter your email"
}
},
{
"uuid": "abc12345-6789-def0-1234-56789abcdef0",
"type": "TITLE",
"groupUuid": "0a1b2c3d-4e5f-4061-a273-8495a6b7c8d9",
"groupType": "QUESTION",
"payload": {
"html": "Message"
}
},
{
"uuid": "456789ab-cdef-0123-4567-89abcdef0123",
"type": "TEXTAREA",
"groupUuid": "1c2d3e4f-5061-4728-b394-a5b6c7d8e9f0",
"groupType": "TEXTAREA",
"payload": {
"isRequired": true,
"placeholder": "Enter your message"
}
}
]
}'
```
This example adds in total 7 blocks to the form:
1. The form title
2. A title block for the name field
3. A required text input block for the name field
4. A title block for the email field
5. A required email input block for the email field
6. A title block for the message field
7. A required large text input block for the message field
## Response
The API will respond with a 201 status code and with some form meta data:
```json theme={null}
{
"id": "m2fK5R",
"name": "Contact form",
"workspaceId": "kb3o5R",
"organizationId": "atL65s",
"status": "PUBLISHED",
"hasDraftBlocks": false,
"isClosed": false,
"updatedAt": "2024-12-20T10:34:19.262Z",
"createdAt": "2024-12-20T10:34:19.262Z"
}
```
The form that was created should now show up in the Tally dashboard & look like this.
# Creating a dropdown
Source: https://developers.tally.so/documentation/creating-a-dropdown
Learn how to create a form with a dropdown using the Tally API
## Prerequisites
* A Tally account
* An API key
## Request
To create a form with a dropdown, you'll need to send a POST request with the form blocks, including the dropdown options. Each option is represented as a `DROPDOWN_OPTION` block.
```bash theme={null}
curl -X POST 'https://api.tally.so/forms' \
-H 'Authorization: Bearer ' \
-H 'Content-Type: application/json' \
-d '{
"status": "PUBLISHED",
"blocks": [
{
"uuid": "6ef8675d-33cb-419b-a81e-93982e726f2e",
"type": "FORM_TITLE",
"groupUuid": "073c835f-7ad4-459c-866d-4108b6b7e2e1",
"groupType": "TEXT",
"payload": {
"title": "Dropdown example",
"html": "Dropdown example"
}
},
{
"uuid": "2515b4dd-54e3-4502-afe6-074ad5019b44",
"type": "TITLE",
"groupUuid": "22a0af81-0117-4931-806f-2b83e374275b",
"groupType": "QUESTION",
"payload": {
"html": "What'\''s your favorite color?"
}
},
{
"uuid": "338631d5-64b0-4a55-8219-17658e66196b",
"type": "DROPDOWN_OPTION",
"groupUuid": "aa64831b-8695-4887-afba-31c07034cd77",
"groupType": "DROPDOWN",
"payload": {
"index": 0,
"isFirst": true,
"isLast": false,
"text": "Red"
}
},
{
"uuid": "4c8fe10a-b07e-407e-9347-f64d73a9ba9a",
"type": "DROPDOWN_OPTION",
"groupUuid": "aa64831b-8695-4887-afba-31c07034cd77",
"groupType": "DROPDOWN",
"payload": {
"index": 1,
"isFirst": false,
"isLast": false,
"text": "Green"
}
},
{
"uuid": "3bddc101-571b-4f00-aa7a-30ee629441bc",
"type": "DROPDOWN_OPTION",
"groupUuid": "aa64831b-8695-4887-afba-31c07034cd77",
"groupType": "DROPDOWN",
"payload": {
"index": 2,
"isFirst": false,
"isLast": true,
"text": "Blue"
}
}
]
}'
```
All dropdown options must share the same `groupUuid`. This groups them together as options for the
same dropdown. Each option needs a sequential `index` (starting at 0), and the `isFirst`/`isLast`
flags must be `true` on the first and last option respectively (`false` everywhere else).
## Response
The API will respond with a 200 status code and return the newly created form:
```json theme={null}
{
"id": "m2fK5R",
"name": "Dropdown example",
"workspaceId": "kb3o5R",
"organizationId": "atL65s",
"status": "PUBLISHED",
"hasDraftBlocks": false,
"isClosed": false,
"updatedAt": "2024-12-20T10:34:19.262Z",
"createdAt": "2024-12-20T10:34:19.262Z"
}
```
Your form will now be created with a dropdown containing the three color options.
# Creating a form
Source: https://developers.tally.so/documentation/creating-a-form
Creating an empty form using the Tally API
## Prerequisites
* A Tally account
* An API key
## Request
To create a form, send a POST request to the `/forms` endpoint with the following payload:
```bash theme={null}
curl -X POST 'https://api.tally.so/forms' \
-H 'Authorization: Bearer ' \
-H 'Content-Type: application/json' \
-d '{
"status": "PUBLISHED",
"blocks": [
{
"uuid": "6ef8675d-33cb-419b-a81e-93982e726f2e",
"type": "FORM_TITLE",
"groupUuid": "073c835f-7ad4-459c-866d-4108b6b7e2e1",
"groupType": "TEXT",
"payload": {
"title": "Test",
"html": "Test"
}
}
]
}'
```
Each block requires a unique UUID. You can generate UUIDs using any standard UUID library.
## Response
The API will respond with a 201 status code and with some form meta data:
```json theme={null}
{
"id": "m2fK5R",
"name": "Test",
"workspaceId": "kb3o5R",
"organizationId": "atL65s",
"status": "PUBLISHED",
"hasDraftBlocks": false,
"isClosed": false,
"updatedAt": "2024-12-20T10:34:19.262Z",
"createdAt": "2024-12-20T10:34:19.262Z"
}
```
Your form should now show up in the Tally dashboard. And when you open it, you should see the empty form with just a title "Test".
# Creating a form with settings
Source: https://developers.tally.so/documentation/creating-a-form-with-settings
Learn how to create a form with settings using the Tally API
## Prerequisites
* A Tally account
* An API key
## Request
To create a form with settings, you'll need to send a POST request with the form blocks, including the settings.
In this example we'll configure the following settings;
* French language
* A closing date & time of of 2026-01-09, 09:41 (Paris time)
* A submissions limit of 42
* A unique submission key of the `Email` field
* A redirect on completion of the `URL` field
* A self email notification to `me@company.com`
* A self email reply to `hello@company.com`
* A custom theme with some specific colors & CSS
```bash theme={null}
curl -X POST 'https://api.tally.so/forms' \
-H 'Authorization: Bearer tly-31Aio2vZNKwxGSmaDgutZHLaCg3s7R6c' \
-H 'Content-Type: application/json' \
-d '{
"status": "PUBLISHED",
"blocks": [
{
"uuid": "ea43ce44-71ae-4e79-b6c2-40e739f61c4b",
"type": "FORM_TITLE",
"groupUuid": "36cfc6e4-6c15-495b-a415-be648f3214b6",
"groupType": "TEXT",
"payload": {
"html": "Hello world"
}
},
{
"uuid": "1ff064ca-d869-48f2-89eb-bba61101385b",
"type": "TITLE",
"groupUuid": "aa1fe42e-4ba9-4e15-a63f-fb5f7dd5d5d7",
"groupType": "QUESTION",
"payload": {
"html": "Email"
}
},
{
"uuid": "3f437d91-9501-4a73-b793-0abd9585d55a",
"type": "INPUT_EMAIL",
"groupUuid": "6f34fcbe-4d2e-49ca-94c5-395809e7e9e6",
"groupType": "INPUT_EMAIL",
"payload": {
"isRequired": true,
"placeholder": ""
}
},
{
"uuid": "04e62978-23f7-4121-8f9b-6c37359e60aa",
"type": "TITLE",
"groupUuid": "4cf183be-7eea-4a7b-ab1e-3caa77995d0d",
"groupType": "QUESTION",
"payload": {
"html": "URL"
}
},
{
"uuid": "6033c312-df41-4cae-9ee4-b3893d0a8f5a",
"type": "INPUT_LINK",
"groupUuid": "be4ecfde-635e-4a48-bee5-e142907f4c25",
"groupType": "INPUT_LINK",
"payload": {
"isRequired": true,
"placeholder": ""
}
}
],
"settings": {
"language": "fr",
"closeTimezone": "Europe/Paris",
"closeDate": "2026-01-09",
"closeTime": "09:41",
"submissionsLimit": 42,
"uniqueSubmissionKey": {
"html": "@Email",
"mentions": [
{
"uuid": "36d6ef12-d5b0-4491-b675-5c01cb4799a0",
"field": {
"uuid": "6f34fcbe-4d2e-49ca-94c5-395809e7e9e6",
"type": "INPUT_FIELD",
"questionType": "INPUT_EMAIL",
"blockGroupUuid": "6f34fcbe-4d2e-49ca-94c5-395809e7e9e6",
"title": "Email"
}
}
]
},
"redirectOnCompletion": {
"html": "@URL",
"mentions": [
{
"uuid": "42283ab9-9efe-4b58-bac5-b4fbc04ab945",
"field": {
"uuid": "be4ecfde-635e-4a48-bee5-e142907f4c25",
"type": "INPUT_FIELD",
"questionType": "INPUT_LINK",
"blockGroupUuid": "be4ecfde-635e-4a48-bee5-e142907f4c25",
"title": "URL"
}
}
]
},
"hasSelfEmailNotifications": true,
"selfEmailTo": {
"html": "me@company.com",
"mentions": []
},
"selfEmailReplyTo": {
"html": "hello@company.com",
"mentions": []
},
"selfEmailSubject": null,
"selfEmailFromName": null,
"selfEmailBody": {
"html": "URL: @URL",
"mentions": [
{
"uuid": "d036b126-f593-417d-b9a7-0a50db496625",
"field": {
"uuid": "be4ecfde-635e-4a48-bee5-e142907f4c25",
"type": "INPUT_FIELD",
"questionType": "INPUT_LINK",
"blockGroupUuid": "be4ecfde-635e-4a48-bee5-e142907f4c25",
"title": "URL"
}
}
]
},
"styles": {
"theme": "CUSTOM",
"color": {
"background": "#ffffff",
"text": "#37352f",
"accent": "#007aff",
"buttonBackground": "#007aff",
"buttonText": "#ffffff"
},
"css": ".tally-submit-button svg {\n display: none;\n}",
"direction": "ltr"
}
}
}'
```
## Response
The API will respond with a 200 status code and return the newly created form:
```json theme={null}
{
"numberOfSubmissions": 0,
"id": "w4AGDr",
"name": "Hello world",
"workspaceId": "qnGe3Z",
"organizationId": "kwob3J",
"status": "PUBLISHED",
"updatedAt": "2025-01-14T14:01:47.222Z",
"createdAt": "2025-01-14T14:01:47.222Z",
"isClosed": false
}
```
Your form will now be created with the settings you provided.
# Creating a mention
Source: https://developers.tally.so/documentation/creating-a-mention
Learn how to create a form with a mention using the Tally API
## Prerequisites
* A Tally account
* An API key
## Request
To create a form with a mention, you'll need to send a POST request with the form blocks, including the mentions as part of the `TITLE` block.
```bash theme={null}
curl -X POST 'https://api.tally.so/forms' \
-H 'Authorization: Bearer ' \
-H 'Content-Type: application/json' \
-d '{
"status": "PUBLISHED",
"blocks": [
{
"uuid": "e206d8e8-70ad-45c4-b731-775049b43e73",
"type": "FORM_TITLE",
"groupUuid": "8c6a61d5-0489-46ec-9498-930907ffb306",
"groupType": "TEXT",
"payload": {
"html": "Hello @name",
"mentions": [
{
"uuid": "0f7b3637-61b6-4faa-a93a-a6a31ff5ac63",
"field": {
"uuid": "16826368-6cce-4066-b1da-be466f851c2d",
"type": "HIDDEN_FIELD",
"questionType": "HIDDEN_FIELDS",
"blockGroupUuid": "203e6532-22a0-4421-b720-5d88d603e618",
"title": "name"
},
"defaultValue": "there"
}
]
}
},
{
"uuid": "98eada2b-9a1e-430a-b20e-ff94ab01b5ea",
"type": "HIDDEN_FIELDS",
"groupUuid": "203e6532-22a0-4421-b720-5d88d603e618",
"groupType": "HIDDEN_FIELDS",
"payload": {
"hiddenFields": [
{
"uuid": "16826368-6cce-4066-b1da-be466f851c2d",
"name": "name"
}
]
}
}
]
}'
```
## Response
The API will respond with a 200 status code and return the newly created form:
```json theme={null}
{
"numberOfSubmissions": 0,
"id": "w4AGDr",
"name": "Hello @name",
"workspaceId": "qnGe3Z",
"organizationId": "kwob3J",
"status": "PUBLISHED",
"updatedAt": "2025-01-14T14:01:47.222Z",
"createdAt": "2025-01-14T14:01:47.222Z",
"isClosed": false
}
```
Your form will now be created with a mention of the `name` hidden field.
Which can be auto populated using the `name` query parameter.
# Fetching form submissions
Source: https://developers.tally.so/documentation/fetching-form-submissions
Retrieve submissions for a form using the Tally API
## Prerequisites
* A Tally account
* An API key
* An existing form with submissions
## Request
To fetch submissions for a form, send a GET request to the `/forms/:id/submissions` endpoint:
```bash theme={null}
curl -X GET 'https://api.tally.so/forms/:id/submissions' \
-H 'Authorization: Bearer ' \
-H 'Content-Type: application/json'
```
## Response
The API will respond with a 200 status code and return an object containing the submissions and form metadata:
```json theme={null}
{
"page": 1,
"limit": 50,
"hasMore": false,
"totalNumberOfSubmissionsPerFilter": {
"all": 4,
"completed": 4,
"partial": 0
},
"questions": [
{
"id": "EKOE2N",
"type": "INPUT_TEXT",
"title": "First name",
"fields": [
{
"uuid": "21dd98ef-4c54-4e77-bcc6-7ec79409b3ea",
"type": "INPUT_FIELD",
"questionType": "INPUT_TEXT",
"title": "First name"
}
]
}
],
"submissions": [
{
"id": "GG6z5L",
"formId": "mexJoq",
"respondentId": "jzQdR9",
"isCompleted": true,
"submittedAt": "2024-12-30T09:02:01.000Z",
"responses": [
{
"id": "4r5rAWb",
"questionId": "EKOE2N",
"answer": "Filip"
}
]
},
{
"id": "2WXeKV",
"formId": "mexJoq",
"respondentId": "kzQdR0",
"isCompleted": true,
"submittedAt": "2024-12-30T08:57:52.000Z",
"responses": [
{
"id": "eR4RxeQ",
"questionId": "EKOE2N",
"answer": "Marie"
}
]
},
{
"id": "GPWkYL",
"formId": "mexJoq",
"respondentId": "lzQdR1",
"isCompleted": true,
"submittedAt": "2024-12-27T10:23:16.000Z",
"responses": [
{
"id": "GlZqg8Q",
"questionId": "EKOE2N",
"answer": "Wouter"
}
]
},
{
"id": "MxBPJ8",
"formId": "mexJoq",
"respondentId": "mzQdR2",
"isCompleted": true,
"submittedAt": "2024-12-27T10:22:38.000Z",
"responses": [
{
"id": "X0p8gDO",
"questionId": "EKOE2N",
"answer": "Frederik"
}
]
}
]
}
```
# Styling title blocks
Source: https://developers.tally.so/documentation/styling-title-blocks
Learn how to style your form title blocks using the Tally API
## Prerequisites
* A Tally account
* An API key
* An existing form
## Request
To style blocks, you can use basic HTML markup in the `html` field.
```bash theme={null}
curl -X PATCH 'https://api.tally.so/forms/:id' \
-H 'Authorization: Bearer ' \
-H 'Content-Type: application/json' \
-d '{
"name": "Test",
"status": "PUBLISHED",
"blocks": [
{
"uuid": "6ef8675d-33cb-419b-a81e-93982e726f2e",
"type": "FORM_TITLE",
"groupUuid": "073c835f-7ad4-459c-866d-4108b6b7e2e1",
"groupType": "TEXT",
"payload": {
"html": "Test",
"title": "Test"
}
},
{
"uuid": "48b4cdf3-2c9d-47d3-b8fb-b0ccabc5cd84",
"type": "TITLE",
"groupUuid": "93034250-5f05-4710-b8e0-5c9145c5b9ea",
"groupType": "QUESTION",
"payload": {
"html": "What'\''s your name?"
}
},
{
"uuid": "884ff838-97f9-4ac9-8db1-31aa052df988",
"type": "INPUT_TEXT",
"groupUuid": "3287d15c-c2b2-4f84-a915-bc57380a4b51",
"groupType": "INPUT_TEXT",
"payload": {
"isRequired": true,
"placeholder": ""
}
}
]
}'
```
In this example, we'll be styling "name" in the question title block.
## Response
The API will respond with a 200 status code and return the some meta data about the form:
```json theme={null}
{
"id": "m2fK5R",
"name": "Test",
"workspaceId": "kb3o5R",
"organizationId": "atL65s",
"status": "PUBLISHED",
"hasDraftBlocks": false,
"isClosed": false,
"updatedAt": "2024-12-20T10:34:19.262Z",
"createdAt": "2024-12-20T10:34:19.262Z"
}
```
Your form will now display with a styled title block where "name" appears in italic, bold, and in red (#eb4d4b).
# TallyBot
Source: https://developers.tally.so/documentation/tally-bot
Learn about TallyBot and how we use automated crawling to enhance form creation
## What is TallyBot?
TallyBot is Tally's web crawler that automatically visits websites to gather information and enhance your form-building experience. Our bot operates with the user agent:
```
TallyBot/1.0 (+https://tally.so/bot)
```
## What We Do
TallyBot serves two primary purposes to improve your Tally experience:
### 1. Form Creation Enhancement
* **Content Analysis**: We extract relevant information from websites you reference to suggest better form titles, descriptions, and field labels
* **Context Understanding**: When you're creating forms based on web content, TallyBot helps understand the context to provide more relevant suggestions
### 2. Resource Validation
* **Link Verification**: We check if external resources, links, or assets you reference in your forms are accessible and valid
* **Asset Availability**: Verify that images, documents, or other media you embed in forms are reachable
## Technical Details
### Request Behavior
* **Rate Limiting**: TallyBot respects standard rate limiting practices and won't overwhelm your servers
* **robots.txt**: We honor robots.txt directives and crawling restrictions
* **User Agent**: All requests include our identifiable user agent string for transparency
### Respectful Crawling
* **Minimal Impact**: We minimize server load by making efficient, targeted requests
* **Cache-Friendly**: We respect cache headers and avoid unnecessary repeat requests
* **Standard Protocols**: We follow web standards and best practices for automated crawling
## Contact & Support
If you have questions about TallyBot's activity on your website or need to report an issue, you can reach out to us via [https://tally.so/support](https://tally.so/support).
## Blocking TallyBot
If you need to prevent TallyBot from accessing your website, you can:
### Using robots.txt
```txt theme={null}
User-agent: TallyBot
Disallow: /
```
***
TallyBot helps make form creation more intelligent and ensures the resources you use are reliable. We're committed to respectful crawling practices that benefit both form creators and website owners.
# Code injection
Source: https://developers.tally.so/widgets/code-injection
Run custom JavaScript inside a Tally form hosted on your own custom domain.
When you serve a form via your own [custom domain](https://tally.so/help/custom-domains),
you can inject custom JavaScript that runs **inside the form page itself** — no embed or
popup involved. Use it to prefill fields from an API call, read values entered by the
respondent, or read previously saved answers from the browser.
Paste your code into the **Code injection** box of your custom domain settings.
## Wait for the DOM
Wrap your code in a `DOMContentLoaded` event handler so the form has finished rendering
before you query its inputs.
```javascript theme={null}
document.addEventListener('DOMContentLoaded', function () {
// Your code goes here
// ...
});
```
## Read an input element
Each block in a Tally form has a stable UUID — you can find it by inspecting the rendered
form in your browser's DevTools. Pass that UUID to `document.getElementById()` to get the
underlying input element.
```javascript theme={null}
document.addEventListener('DOMContentLoaded', function () {
// You can find the input's ID by inspecting your form
const emailInput = document.getElementById('c1cbc8e4-b2f3-4e63-a683-ec9eadbcb022');
});
```
## Set a value on an input element
The form is a React app, so simply assigning to `.value` won't update its state — React's
synthetic event system needs to see a real input event. The snippet below uses the native
setter and dispatches a bubbling `input` event so React picks the change up.
```javascript theme={null}
document.addEventListener('DOMContentLoaded', async function () {
// We get the input element
const emailInput = document.getElementById('c1cbc8e4-b2f3-4e63-a683-ec9eadbcb022');
// Get the email that was typed in
const email = emailInput.value;
// Do an API lookup using the email to get the user's unique identifier
const response = await fetch(`https://api.example.com/getUserId?email=${email}`);
const { userId } = await response.json();
// Get the target input and set its value
const userIdInput = document.getElementById('184b69ee-0c9f-449a-b361-b5250ccd2cb3');
// This is necessary to bubble the event up to the input and update the React app state
const nativeInputValueSetter = Object.getOwnPropertyDescriptor(
window.HTMLInputElement.prototype,
'value',
).set;
nativeInputValueSetter.call(userIdInput, userId);
userIdInput.dispatchEvent(new Event('input', { bubbles: true }));
});
```
## Read previously entered answers
Tally persists in-progress answers to the browser's `localStorage` under a key derived from
the form ID. You can read them out at any time:
```javascript theme={null}
// You can find the form ID in the URL of the form pages
// Example: https://tally.so/forms/mRoDv3/share
const formId = 'mRoDv3';
let data = localStorage.getItem(`FORM_DATA_${formId}`);
if (data) {
data = JSON.parse(data);
}
```
## Events
Code injection has access to the same JavaScript events as embeds and popups, dispatched
as `CustomEvent`s on `window` rather than as `postMessage` payloads. See
[Events](/widgets/events) for the full payload reference and listener patterns.
# Embeds
Source: https://developers.tally.so/widgets/embeds
Render a Tally form inline on your website using an iframe and the Tally widget script.
The standard embed renders a Tally form inside an `