Base URL and request format
Every endpoint on this page is relative to https://formy.co.il/api. Send and accept JSON: set Accept: application/json and, on requests with a body, Content-Type: application/json. There is no version segment in the path.
The API has two groups of routes:
/open/..., the product's own API: workspaces, forms and form integrations. A token reaches only the routes listed under [abilities](#abilities)./external/..., small, stable endpoints for automation platforms and scripts: validate a token, list workspaces, forms and fields, subscribe a Make webhook, and send a document for signature. They are documented on Automation endpoints and Signing requests.
Where a path has {form}, you can pass the form's numeric ID or its slug (the last part of its public link, formy.co.il/forms/<slug>). {workspace} is the workspace's numeric ID.
Personal access tokens
A personal access token acts as the person who created it, in every workspace that person belongs to. Abilities narrow what the token may do; the person's role in each workspace still applies on top, so a token belonging to a read-only member cannot edit anything in that workspace.
Create a token
- In Formy, open your account settings and the גישה ל-API tab.
- Click יצירת API Access Token חדש.
- Give it a name under שם that says what will use it, such as
CRM sync. - Under הרשאות, keep only what that integration needs. All five abilities are ticked when the dialog opens.
- Click יצירת API Access Token and copy the token with העתקת ה-Token. It is shown once.
The same tab lists your tokens with their abilities and deletes them. A deleted token stops working at once and answers 401. Tokens do not expire on their own, so delete the ones you no longer use and keep a separate token for each integration.
Send it
curl https://formy.co.il/api/external/validate \
-H "Authorization: Bearer $FORMY_TOKEN" \
-H "Accept: application/json"{
"name": "Dana Cohen",
"email": "dana@example.com"
}A token is its number, a |, and 48 letters and digits, such as 123| followed by the rest. Store it as a secret: anyone who has it can do everything its abilities allow, as you.
Abilities and the routes each one opens
Formy decides access per route. Each route a token can call needs one ability, either of two, or both of two, as listed below. A token without the ability gets 403. A route that is not on this list answers 404 to every token, so that a token cannot discover what exists.
| Ability | Name in the dialog | What it opens |
|---|---|---|
forms-read | טפסים - קריאה | Read forms and their definitions, list a workspace's forms and fields. Never responses. |
forms-write | טפסים - כתיבה | Create and update forms, publish or unpublish, rename, restore from the trash, and send documents for signature. Never delete. |
manage-integrations | ניהול אינטגרציות | Create, change, pause and delete a form's integrations, read their delivery history, subscribe Make hooks. Also reads the form itself. |
workspaces-read | סביבת עבודה - קריאה | List your workspaces and their members. |
workspaces-write | סביבת עבודה - כתיבה | Create and rename workspaces, and list pending invitations (workspace admins). |
Older tokens may also carry workspace-users-read or workspace-users-write. No route checks either one, and the dialog no longer offers them.
Workspaces
| Route | Ability | What it does |
|---|---|---|
GET /open/workspaces | workspaces-read | List the workspaces you belong to, with their members and roles. |
POST /open/workspaces/create | workspaces-write | Create a workspace, within your plan's workspace limit. |
PUT /open/workspaces/{workspace} | workspaces-write | Rename a workspace and set its icon. Not open to read-only members. |
GET /open/workspaces/{workspace}/users | workspaces-read | List a workspace's members. |
GET /open/workspaces/{workspace}/invites | workspaces-write | List pending invitations. Workspace admins only. |
Forms
| Route | Ability | What it does |
|---|---|---|
GET /open/forms | forms-read | Every form in every workspace you belong to, in one list. |
GET /open/workspaces/{workspace}/forms | forms-read | One workspace's forms, paginated, with search and filters. |
GET /open/workspaces/{workspace}/forms/trashed | workspaces-read and forms-read | Forms in the workspace's trash. |
GET /open/forms/{form} | forms-read or manage-integrations | One form's full definition, with its revision and ETag. |
POST /open/forms | forms-write | Create a form from a definition. |
PUT /open/forms/{form} | forms-write | Replace a form's definition. Needs the revision you read. |
POST /open/forms/{slug}/restore | forms-write | Take a form out of the trash. |
GET /open/dashboard/forms | forms-read | The dashboard's form list for one workspace, 10 a page. |
PATCH /open/dashboard/forms/{form}/visibility | forms-write | Publish a form or turn it back into a draft. |
PATCH /open/dashboard/forms/{form}/rename | forms-write | Rename a form. |
Form integrations
| Route | Ability | What it does |
|---|---|---|
GET /open/forms/{form}/integrations | manage-integrations | A form's integrations, each with its last delivery. |
POST /open/forms/{form}/integrations | manage-integrations | Add an integration, such as a webhook. |
PUT /open/forms/{form}/integrations/{integration} | manage-integrations | Change an integration's settings. |
PUT /open/forms/{form}/integrations/{integration}/status | manage-integrations | Pause or resume an integration. |
DELETE /open/forms/{form}/integrations/{integration} | manage-integrations | Delete an integration. |
GET /open/forms/{form}/integrations/{integration}/events | manage-integrations | An integration's delivery history. |
Automation endpoints
| Route | Ability | What it does |
|---|---|---|
GET /external/validate | any token | Check that a token is valid; answers with its owner's name and email. |
GET /external/workspaces | workspaces-read | Your workspaces, as {id, name, label, value}. |
GET /external/forms | forms-read | The forms of one workspace (workspace_id), as {id, name, label, value, slug, visibility}. |
GET /external/forms/{form}/fields | forms-read | A form's answerable fields: id, name, type, required, hidden. |
POST /external/forms/{form}/signing-requests | forms-write | Send one filled-in document to one person for signature. |
POST /external/make/webhook | manage-integrations | Subscribe a Make webhook URL to a form. |
DELETE /external/make/webhook | manage-integrations | Unsubscribe it. |
GET /external/make/submissions/recent | manage-integrations | One sample delivery for field mapping. |
GET /external/zapier/validate | any token | Legacy copy of /external/validate. |
GET /external/zapier/workspaces | workspaces-read | Legacy copy of /external/workspaces. |
GET /external/zapier/forms | forms-read | Legacy copy of /external/forms. |
POST /external/zapier/webhook | manage-integrations | Legacy: subscribe a Zapier hook. |
DELETE /external/zapier/webhook | manage-integrations | Legacy: unsubscribe it. |
GET /external/zapier/submissions/recent | manage-integrations | Legacy: recent submissions for Zapier's polling test. |
What a token cannot do
These operations exist in the product but only for a person signed in to Formy in a browser. A token gets 404 for each of them, even with every ability. That is deliberate, but it means a 404 here is about permission, not a typo in the path.
- Read, list, update or delete responses (submissions)
- Export responses, and poll an export's status
- A response's PDF or file links
- Delete a form, empty the trash, duplicate a form or move it to another workspace
- Delete or leave a workspace
- Add or remove members, change a role, resend or cancel an invitation
- Contacts, bulk send, signing-round controls, folders, statistics and the response summary
To get responses into another system, use a webhook (every completed response, signed, retried for a day), Make or Google Sheets. To download them yourself, export from the responses table: see responses and exports.
Workspaces
GET /open/workspaces lists every workspace you belong to, with its members and their roles. GET /external/workspaces returns the short form an automation dropdown needs; see Automation endpoints.
curl https://formy.co.il/api/open/workspaces \
-H "Authorization: Bearer $FORMY_TOKEN" -H "Accept: application/json"To create one, POST /open/workspaces/create with a name (required) and an optional emoji for its icon. Your plan sets how many workspaces you can have; over the limit the call answers with a [plan-limit error](#errors). PUT /open/workspaces/{workspace} takes the same two fields and replaces both, so send the emoji again if you want to keep it.
curl -X POST https://formy.co.il/api/open/workspaces/create \
-H "Authorization: Bearer $FORMY_TOKEN" -H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{"name": "Clinic intake"}'Forms
GET /open/forms returns every form in every workspace you belong to, in one unpaginated list. For one workspace, GET /open/workspaces/{workspace}/forms is paginated and accepts:
| Parameter | Values |
|---|---|
page | Page number, from 1. |
per_page | Forms per page: 10 by default, 100 at most. |
search | Text in the form's title, up to 200 characters. |
status | all (default), public or draft. |
sort | recent (default), created or submissions. |
folder_id, tag, favorite | Narrow to a folder, a tag, or your favourites. |
GET /open/forms/{form} returns the whole definition: settings, properties (the fields, each with its id, type and name), definition_revision and etag. A token with only manage-integrations can read it too, so an integration can look up the form it serves.
Create and update
POST /open/forms creates a form from a definition. It needs workspace_id, title and properties, plus the presentation settings the editor saves (visibility, language, theme, presentation_style, width, size, border_radius, dark_mode, color, uppercase_labels, no_branding, transparent_background). The definition format is the editor's own, so the reliable way to build one is to read a form you made in the editor and change it.
PUT /open/forms/{form} replaces the definition. Send the whole definition back with the expected_revision you read, or an If-Match header with its ETag; see [revisions](#revisions). Plan limits apply exactly as in the editor: a setting your plan does not include is removed rather than saved, and the response lists what was removed under plan_strip_warnings. The response also carries the new definition_revision and etag.
Smaller writes have their own routes: PATCH /open/dashboard/forms/{form}/visibility with visibility (public or draft) and PATCH /open/dashboard/forms/{form}/rename with title, both with expected_revision. POST /open/forms/{slug}/restore takes a form out of the trash. Deleting a form is not available to tokens.
Form integrations and webhooks by API
Everything on a form's אינטגרציות tab is an integration: email, Slack, Google Sheets, a webhook and the rest. With manage-integrations you can manage them by API. A webhook is the one most often created by code:
curl -X POST https://formy.co.il/api/open/forms/service-agreement/integrations \
-H "Authorization: Bearer $FORMY_TOKEN" -H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{
"integration_id": "webhook",
"status": "active",
"data": {
"webhook_url": "https://example.com/hooks/formy",
"webhook_secret": "a-long-random-secret-value",
"webhook_headers": { "X-Api-Key": "your-own-key" }
},
"logic": null
}'status is active or inactive. logic holds the conditions under which the integration runs, the same ones as מתי האינטגרציה תרוץ? in the product; null runs it on every response. The webhook's own rules (HTTPS only, a public address, a secret of at least 12 characters, at most 10 custom headers) are on the webhooks page.
The response, and GET .../integrations, return each integration with its settings, including the webhook's secret and custom headers. Treat a token with manage-integrations as able to read them.
PUT .../integrations/{integration} changes the settings with the same body, PUT .../integrations/{integration}/status pauses or resumes it, and DELETE removes it. GET .../integrations/{integration}/events returns its delivery history, the same list the product shows under אירועים קודמים.
Revisions: never overwrite someone else's change
Every saved form has a definition_revision, a number that goes up on each save, and an etag built from it. A write that changes a form must say which revision it was based on, as expected_revision in the body or as If-Match: <etag>. If both are sent, they must agree.
| Status | When |
|---|---|
428 | No revision was sent. Read the form first. |
412 | The form changed since you read it. Nothing was saved; the response carries the current definition_revision and etag. Read it again, re-apply your change, and retry. |
422 | The revision is malformed, or the body and the header disagree. |
Creating a form needs no revision; the response carries the first one. A signing request also checks the revision, as expected_form_revision, so a document is never sent from a form that changed under you.
Errors
Errors are JSON with a message, in Hebrew except for the missing-ability 403. Validation errors (422) add an errors object keyed by field, and revision errors add a code.
| Status | Meaning | What to do |
|---|---|---|
401 | No token, an unknown token, or a deleted one. | Send Authorization: Bearer <token>, or create a new token. |
403 | The token lacks the ability the route needs, your role in the workspace does not allow it, or a plan limit was reached ("type": "plan_limit"). | Check the ability table; for a plan limit, read code and target_plan. |
404 | The route is not open to tokens, the form or workspace does not exist, or it is not in your workspaces. | Check the route is in the ability table, then the ID or slug. |
412 | The form changed since the revision you sent. | Read it again and retry. |
422 | The body did not pass validation. | Read errors. |
428 | A write needs a revision and none was sent. | Send expected_revision or If-Match. |
429 | Rate limited. | Wait for Retry-After seconds. |
5xx | A failure on Formy's side. | Retry later with backoff. |
{
"message": "נדרשת התחברות."
}{
"message": "Invalid ability provided."
}{
"message": "המשאב המבוקש לא נמצא."
}{
"type": "plan_limit",
"code": "workspaces",
"feature": "workspaces",
"limit": 1,
"current": 1,
"target_plan": "pro",
"message": "…",
"context": null
}code names the limit and target_plan the cheapest plan that lifts it.Rate limits
Limits are counted per person (all of a person's tokens together) and per minute:
| Routes | Limit |
|---|---|
/external/... | 60 requests a minute across all of them |
/open/... | 600 requests a minute for each method and route |
POST /open/workspaces/create | 10 a minute |
PATCH /open/dashboard/forms/{form}/visibility and /rename | 60 a minute |
Responses carry X-RateLimit-Limit and X-RateLimit-Remaining. Over the limit you get 429 with Retry-After, the seconds to wait. The MCP server has its own limits.
Questions developers ask
Does the Formy API cost extra, or need a paid plan?
No. Tokens, the API, webhooks and the automation endpoints are on every plan, Free included. What the API does still counts against your plan: a document sent for signature uses your signed-document quota, and a new workspace counts against your workspace limit.
How do I read submissions with the API?
You can't with a token: every submission route answers 404 to one. Add a webhook to the form, and Formy posts each completed response to your server as it arrives, signed and retried for up to a day. For a one-off download, export from the responses table in the product.
Why does my token get 404 on a route that exists?
Because only the routes in the ability table are open to tokens, and every other route answers 404 to a token, so it cannot discover what exists. Check the route is in the table; if it is, check the form or workspace belongs to the token's owner.
Is there an OpenAPI specification or an SDK package?
Not a published one. This reference is the specification, checked against the code; the routes take plain JSON over HTTPS, so any HTTP client works. For embedding forms there is a JavaScript SDK served from formy.co.il.
Can I use OAuth instead of a personal token?
Not for the REST API, which takes personal access tokens only. OAuth is how AI assistants connect to the MCP server, which is a separate endpoint and does not accept API tokens.
Related
- Webhooks: Every completed response, pushed to your server and signed.
- Automation endpoints: Validate, workspaces, forms and fields for Make and scripts.
- Signing requests: Send a filled-in document for signature.
Every page of the docs is listed in Formy developer docs .
Try it on a free account
Every plan includes the API, webhooks, the embed SDK and the MCP server, Free included.
Create a free account