A reference guide for building AI agents: every method, how to authenticate, and the permissions each one needs.
The Tally API is how an app or AI agent works with a Tally account: creating a form, updating its questions, reading the submissions people send in, or managing workspaces and webhooks. Access is granted through an API key or an OAuth token, and either one inherits the full access of the user it belongs to, since Tally has no per-area permissions yet. A change to a response shape ships under a new dated version, and a new submission can be pushed to a registered endpoint rather than polled for.
How an app or AI agent connects to Tally determines what it can reach. There is a route for making calls, a route for receiving submissions as they arrive, and a hosted server that exposes Tally tools to agents, and each is governed by the key or token behind it.
The REST API takes JSON request bodies, returns JSON, and lives at https://api.tally.so. A call authenticates with a Bearer token, either a personal API key or an OAuth access token. List endpoints page with a page number and limit. The path carries no version segment; the version is selected by the key's default or the tally-version header.
Tally POSTs a FORM_RESPONSE payload to a registered URL when a form is submitted. The receiver verifies the Tally-Signature header, an HMAC-SHA256 hash of the raw body computed with the webhook's signing secret, and returns a 2XX within 10 seconds. Webhooks are created through the API or in a form's Integrations tab.
A first-party hosted Model Context Protocol server at https://api.tally.so/mcp lets an AI assistant build Tally forms and retrieve forms or submissions in natural language. It authenticates with OAuth (recommended for assistants that support it) or with a Bearer API key. Tally states the MCP server is in beta and subject to change.
A personal API key is created in the dashboard at Settings, API keys, and is shown only once. It is sent as a Bearer token and reaches all of the user's resources; Tally has no scopes to narrow it. Removing the user from an organization deactivates their keys.
OAuth 2.0 uses the authorization-code flow: an integration sends the user to tally.so/oauth/authorize with response_type=code, then exchanges the code at the token endpoint for an access token that can be refreshed. Tally does not define scopes, so the token, like an API key, reaches all of that user's resources.
The Tally API is split into areas an agent can act on, like forms, the questions and blocks inside them, submissions, workspaces, the organization's people, and webhooks. Each area has its own methods, and a write in some areas changes a live form or removes a response.
Methods for listing, reading, creating, updating, and deleting forms.
Methods for reading and updating the questions and blocks that make up a form.
Methods for listing, reading, and deleting the responses people send in.
Read-only methods for visit, submission, and drop-off statistics on a form.
Methods for listing, reading, creating, updating, and deleting the workspaces that group forms.
Methods for the people in an organization: listing users, removing them, and managing invites.
A read-only method for the current authenticated user.
Methods for creating, listing, updating, and deleting webhooks, and inspecting or retrying their deliveries.
Filter by method, access, or permission, or search any path. Select a row for version detail, rate limits, the related webhook event, and the source.
| Method | Endpoint | What it does | Access | Permission | Version | |
|---|---|---|---|---|---|---|
FormsMethods for listing, reading, creating, updating, and deleting forms.5 | ||||||
| GET | /forms | Return a paginated array of form objects. | read | — | Current | |
Read-only. Tally has no scopes; any valid token reaches all of the user's forms. Acts onform Permission (capability)None required VersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| POST | /forms | Create a new form, optionally from a template or within a specific workspace. | write | — | Current | |
A core write. No scope narrows it; the token's user owns the new form. Acts onform Permission (capability)None required VersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| GET | /forms/{formId} | Return a single form by its ID with all its blocks and settings. | read | — | Current | |
Read-only. Acts onform Permission (capability)None required VersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| PATCH | /forms/{formId} | Update a form's settings, blocks, or status. | write | — | Current | |
Changes a live form. Block payloads are validated against the schema, so an invalid structure returns a 400. Acts onform Permission (capability)None required VersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| DELETE | /forms/{formId} | Delete a form by its ID and move it to the trash. | write | — | Current | |
Moves the form to trash rather than erasing it immediately. Acts onform Permission (capability)None required VersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
Questions & blocksMethods for reading and updating the questions and blocks that make up a form.4 | ||||||
| GET | /forms/{formId}/questions | Return a list of all questions in a form, with a flag for whether the form has responses. | read | — | Current | |
Read-only. Acts onquestion Permission (capability)None required VersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| PATCH | /forms/{formId}/questions/{questionId} | Update a specific question in a form. | write | — | Current | |
Changes what a live form asks. Acts onquestion Permission (capability)None required VersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| GET | /forms/{formId}/blocks | Return a list of all blocks in a form, the ordered pieces that render it. | read | — | Current | |
Read-only. Acts onblock Permission (capability)None required VersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| PATCH | /forms/{formId}/blocks | Update the blocks in a form. | write | — | Current | |
Changes how a live form renders. Block payloads are validated against the schema, so an invalid structure returns a 400. Acts onblock Permission (capability)None required VersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
SubmissionsMethods for listing, reading, and deleting the responses people send in.3 | ||||||
| GET | /forms/{formId}/submissions | Return a paginated list of a form's submissions with their responses. | read | — | Current | |
Read-only. Accepts filter (all, completed, partial), startDate, endDate, and afterId; limit can run up to 500. Acts onsubmission Permission (capability)None required VersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| GET | /forms/{formId}/submissions/{submissionId} | Return a specific submission with all its responses and the form's questions. | read | — | Current | |
Read-only. Returns the answers a person submitted. Acts onsubmission Permission (capability)None required VersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| DELETE | /forms/{formId}/submissions/{submissionId} | Delete a specific submission from a form. | write | — | Current | |
Permanently removes a person's response. Acts onsubmission Permission (capability)None required VersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
AnalyticsRead-only methods for visit, submission, and drop-off statistics on a form.5 | ||||||
| GET | /forms/{formId}/analytics/metrics | Return aggregate metrics for a form, like visits, submissions, and completion rate. | read | — | New | |
Read-only. Returns aggregate counts, not raw responses. Acts onanalytics Permission (capability)None required VersionIntroduced 2026-06-19 Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| GET | /forms/{formId}/analytics/visits | Return visit counts for a form over time. | read | — | New | |
Read-only. Acts onanalytics Permission (capability)None required VersionIntroduced 2026-06-19 Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| GET | /forms/{formId}/analytics/submissions | Return completed and partial submission counts for a form over time. | read | — | New | |
Read-only. Counts only, not the responses themselves. Acts onanalytics Permission (capability)None required VersionIntroduced 2026-06-19 Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| GET | /forms/{formId}/analytics/dimensions | Return visitor breakdowns by source, browser, OS, device, and location. | read | — | New | |
Read-only. Acts onanalytics Permission (capability)None required VersionIntroduced 2026-06-19 Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| GET | /forms/{formId}/analytics/drop-off | Return per-question drop-off statistics for a form. | read | — | New | |
Read-only. Acts onanalytics Permission (capability)None required VersionIntroduced 2026-06-19 Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
WorkspacesMethods for listing, reading, creating, updating, and deleting the workspaces that group forms.5 | ||||||
| GET | /workspaces | Return a paginated array of workspace objects. | read | — | Current | |
Read-only. Acts onworkspace Permission (capability)None required VersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| POST | /workspaces | Create a new workspace. | write | — | Current | |
Requires a Pro subscription on the account. Acts onworkspace Permission (capability)None required VersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| GET | /workspaces/{workspaceId} | Return a single workspace by its ID with its members. | read | — | Current | |
Read-only. Acts onworkspace Permission (capability)None required VersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| PATCH | /workspaces/{workspaceId} | Update a workspace's information by its ID. | write | — | Current | |
Changes a shared workspace's settings. Acts onworkspace Permission (capability)None required VersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| DELETE | /workspaces/{workspaceId} | Delete a workspace and all of its associated forms. | write | — | Current | |
Removes every form inside the workspace along with it. Acts onworkspace Permission (capability)None required VersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
Organization & usersMethods for the people in an organization: listing users, removing them, and managing invites.5 | ||||||
| GET | /organizations/{organizationId}/users | Return a list of all users in an organization. | read | — | Current | |
Read-only. Returns the people in the organization. Acts onuser Permission (capability)None required VersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| DELETE | /organizations/{organizationId}/users/{userId} | Remove a user from an organization. | write | — | Current | |
Removes a person's access; also deactivates that user's API keys. Acts onuser Permission (capability)None required VersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| GET | /organizations/{organizationId}/invites | Return a list of all pending invites in an organization. | read | — | Current | |
Read-only. Acts oninvite Permission (capability)None required VersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| POST | /organizations/{organizationId}/invites | Invite users to join specific workspaces within an organization. | write | — | Current | |
Grants a new person access to the named workspaces. Acts oninvite Permission (capability)None required VersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| DELETE | /organizations/{organizationId}/invites/{inviteId} | Cancel a pending invitation to join workspaces. | write | — | Current | |
Withdraws an invite before it is accepted. Acts oninvite Permission (capability)None required VersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
UserA read-only method for the current authenticated user.1 | ||||||
| GET | /users/me | Return information about the current authenticated user. | read | — | Current | |
Read-only. Replaced the older /me endpoint, deprecated in the 2025-02-01 version. Acts onuser Permission (capability)None required VersionIntroduced 2025-02-01 Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
WebhooksMethods for creating, listing, updating, and deleting webhooks, and inspecting or retrying their deliveries.6 | ||||||
| GET | /webhooks | Return a paginated list of all webhooks. | read | — | Current | |
Read-only. Shows where forms' submissions are being sent. Acts onwebhook Permission (capability)None required VersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| POST | /webhooks | Create a webhook for a form to receive form events at a URL. | write | — | Current | |
Takes formId, url, and eventTypes (FORM_RESPONSE), plus an optional signingSecret and custom HTTP headers. Acts onwebhook Permission (capability)None required VersionAvailable since the API’s base version Webhook event FORM_RESPONSERate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| PATCH | /webhooks/{webhookId} | Update an existing webhook's configuration. | write | — | Current | |
Can change the destination URL or enabled status of a webhook. Acts onwebhook Permission (capability)None required VersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| DELETE | /webhooks/{webhookId} | Delete a webhook. | write | — | Current | |
Stops a form's submissions from being delivered to that URL. Acts onwebhook Permission (capability)None required VersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| GET | /webhooks/{webhookId}/events | Return a paginated list of a webhook's delivery events, with status and retry info. | read | — | Current | |
Read-only. Useful for diagnosing failed deliveries. Acts onwebhook_event Permission (capability)None required VersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| POST | /webhooks/{webhookId}/events/{eventId} | Retry sending a failed webhook delivery event. | write | — | Current | |
Re-sends a previously failed delivery to the endpoint. Acts onwebhook_event Permission (capability)None required VersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
Tally can notify an app when a form is submitted. It sends a FORM_RESPONSE payload describing the response and its fields, so an integration learns about a new submission without polling.
| Event | What it signals | Triggered by |
|---|---|---|
FORM_RESPONSE | A form was submitted. The payload carries an eventId, the eventType, a createdAt timestamp, and a data object with the responseId, formId, formName, and a fields array of each answer's key, label, type, and value. | /webhooks |
Tally limits how fast an app can call, by a request rate measured per minute across the key, and pages list results so a single call returns a bounded set.
Tally allows 100 requests per minute, measured per API key. Going over returns HTTP 429. The docs recommend receiving new submissions through a webhook rather than repeatedly listing them, so polling does not consume the limit. There is no documented per-method cost or weighting; every call counts the same against the per-minute rate.
List endpoints page with a page number and a limit. A response carries pagination metadata, including hasMore, and (from the 2025-02-01 version) wraps the results in an items array. The submissions list also accepts afterId to continue past a known submission and filter, startDate, and endDate to narrow the set. A limit can run up to 500 on the submissions list.
A list page returns a bounded set, up to the limit (as high as 500 on the submissions list, default 50). A webhook receiver must return a 2XX status within 10 seconds, or Tally treats the delivery as failed and the event can be retried.
The status codes an agent should handle, and what to do about each.
| Status | Code | Meaning | What to do |
|---|---|---|---|
| 400 | Bad Request | The request was malformed, for example an invalid block payload structure, which is validated against the schema and rejected. | Fix the request body to match the documented shape and resend. |
| 401 | Unauthorized | No valid Bearer token was provided, or the token is missing or expired. | Send a valid API key or OAuth access token in the Authorization header; refresh the token if it has expired. |
| 403 | Forbidden | The authenticated user is not allowed to perform this request, for example acting on a workspace or organization they cannot access, or an action that needs a Pro subscription. | Use a token for a user with access, or upgrade the plan where the action requires it. |
| 404 | Not Found | The requested resource does not exist or is not visible to this user, for example a wrong form, submission, or workspace ID. | Verify the ID and that it belongs to the authenticated user's account. |
| 429 | Rate Limited | More than 100 requests were made in a minute on the key. | Slow the request rate, and receive new submissions through a webhook rather than polling. |
| 500 | Server Error | An error on Tally's side. | Retry after a short delay, and contact Tally support if it persists. |
Tally pins a dated version to each API key and lets a request override it with a header, so a change to a response shape ships under a new date rather than breaking existing callers.
Five analytics endpoints were added for a form: aggregate metrics, visits over time, submissions over time, visitor dimensions, and per-question drop-off.
Form settings began supporting rich text with HTML and mentions for email and redirect fields.
Submission responses began including preview and PDF URLs.
Block payloads are now validated against the schema, so a request with an invalid block structure is rejected.
Multiple endpoints were added for questions, submissions, organization users and invites, and webhooks, and submission filtering was enhanced.
Forms and workspaces list responses became paginated and wrapped in an items array with pagination metadata, a breaking change to the response shape. A /users/me endpoint was added and the older /me endpoint was deprecated.
The first public version of the Tally API.
A key keeps the version it was created with; move up deliberately by sending the newer date.
Tally API changelog ↗Bollard AI sits between a team's AI agents and Tally. Grant each agent exactly the access it needs, read or write, area by area, and every call is checked and logged, even though a Tally key by itself grants full account access.