{"openapi":"3.1.0","info":{"title":"Clipform API","description":"Build and manage interactive video-style forms. Used by the Clipform ChatGPT integration.\n\n## Rate limiting\n\nEvery response carries the IETF-draft RateLimit header fields so clients can\nself-throttle: `RateLimit-Limit` (the window quota), `RateLimit-Remaining`\n(requests left), and `RateLimit-Reset` (seconds until the window resets). A\nthrottled request returns `429` with a `Retry-After` header (seconds to wait).\n\n## Versioning and deprecation\n\nThe API is versioned in the URL path (`/v1`). Additive, backward-compatible\nchanges (new endpoints, new optional fields) ship within a version without a\nversion bump. Breaking changes ship under a new path prefix (`/v2`). When an\nendpoint is deprecated it is marked `deprecated` in this specification and its\nresponses carry a `Deprecation` header and a `Sunset` header (RFC 8594) giving\nthe date after which it may stop responding - at least 90 days out.\n","version":"1.0.0","contact":{"name":"Clipform","url":"https://clipform.io","email":"support@clipform.io"},"termsOfService":"https://clipform.io/terms"},"servers":[{"url":"https://api.clipform.io/v1","description":"Production","x-internal":false}],"tags":[{"name":"Forms","x-displayName":"Forms","description":"Create, read, update, and delete forms."},{"name":"Nodes","x-displayName":"Nodes","description":"Add, edit, and remove the nodes inside a form, including routing logic."},{"name":"node-media","x-displayName":"Node Media","description":"Attach and manage the video or image media on a node."},{"name":"Tags","x-displayName":"Tags","description":"Organise forms with workspace tags."},{"name":"Analytics","x-displayName":"Analytics","description":"Read funnel analytics, submissions, and results for a form."},{"name":"tracked-links","x-displayName":"Tracked Links","description":"Create and manage tracked share links with click-through analytics."},{"name":"dynamic-links","x-displayName":"Dynamic Links","description":"Create and manage re-pointable links whose target form can be swapped without changing the printed or embedded URL."},{"name":"Webhooks","x-displayName":"Webhooks","description":"The form.completed event Clipform POSTs to your endpoint when a respondent completes a form."},{"name":"Authentication","x-displayName":"Authentication","description":"Verify the caller identity, workspace, and plan."},{"name":"Integrations","x-displayName":"Integrations","description":"The connect lane an installed app uses on a user's behalf - identify the workspace, list its forms, and subscribe to form completions. Used by the Clipform apps for Zapier, Make and n8n."}],"paths":{"/me":{"get":{"operationId":"getMe","tags":["Authentication"],"summary":"Get current user","description":"Returns the authenticated caller's workspace and plan limits.","responses":{"200":{"description":"Identity + plan summary","content":{"application/json":{"schema":{"type":"object","properties":{"auth_mode":{"type":"string","enum":["session","api_key","oauth","anonymous"]},"user_id":{"type":"string","format":"uuid","nullable":true,"description":"Present in session mode only.","maxLength":36},"workspace":{"type":"object","nullable":true,"properties":{"id":{"type":"string","format":"uuid","maxLength":36},"name":{"type":"string","maxLength":2000},"role":{"type":"string","description":"Caller's role in the workspace. Session mode only.","maxLength":2000},"show_branding":{"type":"boolean","description":"Workspace-level branding flag. Session mode only."},"moderate_responses":{"type":"boolean","description":"Workspace-level default for moderating open-ended responses on ingest. Session mode only."}}},"workspaces":{"type":"array","description":"All workspaces the user belongs to in the current company, sorted by name. Session mode only - powers the dashboard workspace switcher.","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","maxLength":36},"name":{"type":"string","maxLength":2000}}},"maxItems":500},"company_id":{"type":"string","format":"uuid","nullable":true,"description":"Company owning the workspace. Null when workspace has no company or in anonymous mode.","maxLength":36},"plan":{"type":"object","properties":{"tier":{"type":"integer","format":"int32","minimum":0,"maximum":2147483647},"name":{"type":"string","maxLength":2000},"node_limit":{"type":"integer","nullable":true,"format":"int32","minimum":0,"maximum":2147483647},"show_branding":{"type":"boolean"},"custom_theme":{"type":"boolean"},"response_limit":{"type":"integer","nullable":true,"format":"int32","minimum":0,"maximum":2147483647}}},"links":{"type":"object","description":"Workspace-level dashboard links. Present only for a non-anonymous caller.","properties":{"dashboard":{"type":"string","format":"uri","description":"Dashboard home for this workspace.","maxLength":2048},"forms":{"type":"string","format":"uri","description":"Forms list for this workspace.","maxLength":2048}}}}}}}}}}},"/connect/me":{"get":{"operationId":"getConnectedWorkspace","tags":["Integrations"],"summary":"Get the connected workspace","description":"Returns the workspace the calling OAuth token or API key is bound to, for use as a connection test.","security":[{"oauth2":[]},{"bearerAuth":[]}],"responses":{"200":{"description":"The workspace this credential is connected to.","content":{"application/json":{"schema":{"type":"object","properties":{"workspace_id":{"type":"string","format":"uuid","example":"550e8400-e29b-41d4-a716-446655440000","maxLength":36},"workspace_name":{"type":"string","example":"Acme Marketing","maxLength":2000}}}}}},"401":{"description":"Missing, invalid, or expired credential.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/connect/forms":{"get":{"operationId":"listConnectForms","tags":["Integrations"],"summary":"List published forms","description":"Lists the workspace's published forms as id, title and share id, for populating a form picker in an integration.","security":[{"oauth2":["forms:read"]},{"bearerAuth":[]}],"responses":{"200":{"description":"Published forms in the connected workspace, most recently updated first.","content":{"application/json":{"schema":{"type":"array","maxItems":1000,"items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","example":"f47ac10b-58cc-4372-a567-0e02b2c3d479","maxLength":36},"title":{"type":"string","example":"Customer Feedback","maxLength":2000},"share_id":{"type":"string","example":"abc12345","maxLength":2000}}}}}}},"403":{"description":"The credential is missing the forms:read scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/connect/hooks":{"post":{"operationId":"subscribeWebhook","tags":["Integrations"],"summary":"Subscribe to form completions","description":"Registers a target URL that receives the form.completed payload for every form in the connected workspace.","security":[{"oauth2":["webhooks:manage"]},{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["targetUrl"],"properties":{"targetUrl":{"type":"string","format":"uri","description":"HTTPS endpoint Clipform POSTs each completion to. Must be publicly resolvable.","example":"https://hook.eu1.make.com/abc123","maxLength":2000}}}}}},"responses":{"201":{"description":"Subscription created, or an existing subscription for the same URL reactivated.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Subscription id - pass it to the unsubscribe operation.","example":"6f4b2c1e-0d3a-4a2b-9c8d-1e2f3a4b5c6d","maxLength":36}}}}}},"400":{"description":"targetUrl is missing or is not a safe public URL.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The credential is missing the webhooks:manage scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/connect/hooks/{hookId}":{"delete":{"operationId":"unsubscribeWebhook","tags":["Integrations"],"summary":"Unsubscribe from form completions","description":"Deactivates a webhook subscription so Clipform stops POSTing completions to its target URL.","security":[{"oauth2":["webhooks:manage"]},{"bearerAuth":[]}],"parameters":[{"name":"hookId","in":"path","required":true,"description":"Subscription id returned when the webhook was registered.","schema":{"type":"string","format":"uuid","example":"6f4b2c1e-0d3a-4a2b-9c8d-1e2f3a4b5c6d","maxLength":36}}],"responses":{"200":{"description":"Subscription deactivated.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}}}}}},"400":{"description":"The subscription id is not a valid identifier.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The subscription belongs to a different workspace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No subscription with that id.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/forms":{"get":{"operationId":"listForms","tags":["Forms"],"summary":"List forms","description":"Lists the forms in a workspace.","parameters":[{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":25,"format":"int32"},"description":"Number of forms per page"},{"name":"cursor","in":"query","schema":{"type":"string","maxLength":2000},"description":"Opaque pagination cursor from a previous response's `next_cursor`"},{"name":"tag","in":"query","schema":{"type":"string","maxLength":2000},"description":"Filter by tag name(s), comma-separated. AND logic - only forms with ALL specified tags are returned."},{"name":"published","in":"query","schema":{"type":"string","enum":["true","false"]},"description":"Filter by live/draft status"},{"name":"deleted","in":"query","schema":{"type":"string","enum":["true","false"]},"description":"Set to true to list only trashed forms instead of active ones."},{"name":"search","in":"query","schema":{"type":"string","maxLength":2000},"description":"Case-insensitive substring search on form title"},{"name":"sort","in":"query","schema":{"type":"string","enum":["created_at","updated_at"],"default":"created_at"},"description":"Sort field"},{"name":"order","in":"query","schema":{"type":"string","enum":["asc","desc"],"default":"desc"},"description":"Sort order"},{"name":"include","in":"query","schema":{"type":"string","maxLength":2000},"description":"Comma-separated list of related resources to embed. Supported values - `tags`."}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Paginated form list","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FormList"}}}},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"$ref":"#/components/responses/RateLimited"}}},"post":{"operationId":"createForm","tags":["Forms"],"summary":"Create a form","description":"Creates a form, optionally with all its nodes in one request.","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["title","workspace_id"],"properties":{"title":{"type":"string","maxLength":200,"description":"Form title"},"workspace_id":{"type":"string","format":"uuid","description":"Target workspace for the new form. Obtain from GET /v1/me.","maxLength":36},"is_live":{"type":"boolean","default":true,"description":"Whether the form is immediately live (online for respondents). Defaults to true so created forms are shareable right away - pass false explicitly to create offline."},"first_run":{"type":"boolean","default":false,"description":"Internal first-run flag. Set by the dashboard cold-start gate when it auto-scaffolds a new user's starter form, to suppress the first_form_created activation milestone - the scaffold is not authoring. Leave unset for normal creates."},"nodes":{"type":"array","minItems":1,"description":"Optional batch build: ordered list of nodes to create with the form, all-or-nothing. Each node matches the add-node shape (type, prompt, label?, required?, config?, options?).","items":{"type":"object","required":["type","prompt"],"properties":{"type":{"type":"string","description":"Node type (see the node-type reference)","maxLength":2000},"prompt":{"type":"string","maxLength":2000},"label":{"type":"string","maxLength":2000},"required":{"type":"boolean","default":true},"config":{"type":"object","description":"Type-specific configuration"},"options":{"type":"array","items":{"type":"object","required":["content"],"properties":{"content":{"type":"string","maxLength":2000},"is_correct":{"type":"boolean"},"score":{"type":"number"},"scores":{"type":"object","additionalProperties":{"type":"number"}}}},"maxItems":500}}},"maxItems":500},"settings":{"type":"object","description":"Form settings applied with a batch build (ignored without nodes). If any node has scored options, show_step_counter and disable_back_navigation default to true unless set explicitly here.","properties":{"show_step_counter":{"type":"boolean"},"disable_back_navigation":{"type":"boolean"},"primary_color":{"type":"string","description":"6-digit hex, e.g. \"#FF5500\"","maxLength":20},"background_color":{"type":"string","description":"6-digit hex","maxLength":20}}}}}}}},"responses":{"201":{"description":"Form created","content":{"application/json":{"schema":{"type":"object","properties":{"form_id":{"type":"string","format":"uuid","maxLength":36},"share_id":{"type":"string","maxLength":64},"form_url":{"type":"string","format":"uri","nullable":true,"description":"Null for a normal authenticated create. For an anonymous caller in the shared public-company workspace (web/bot/email channels), a save/claim link to move the form into a real account. For an MCP-minted anonymous session's first form (#3330), a one-time same-UID claim URL instead - null on any later create reusing that same session.","maxLength":2048},"viewer_url":{"type":"string","format":"uri","description":"A live public URL for an authenticated/claimed workspace. For an MCP-minted anonymous session (#3330), a time-limited `?mode=preview&pt=...` link only the caller can open - never public until the account is claimed and the form is published.","maxLength":2048},"nodes":{"type":"array","description":"Present on batch builds - created nodes in order","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","maxLength":36},"type":{"type":"string","maxLength":2000},"prompt":{"type":"string","maxLength":2000}}},"maxItems":500}}}}}},"401":{"description":"Missing or invalid credentials","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"workspace_id does not match the API key's workspace","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/forms/skeleton":{"post":{"operationId":"createFormSkeleton","tags":["Forms"],"summary":"Fork a form's node-shape","description":"Forks a published form's node types and order into a blank draft, dropping all of its content.","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["source_share_id","workspace_id"],"properties":{"source_share_id":{"type":"string","maxLength":64,"description":"share_id of the published source form to fork the shape of."},"workspace_id":{"type":"string","format":"uuid","description":"Target workspace for the new draft. Obtain from GET /v1/me.","maxLength":36}}}}}},"responses":{"201":{"description":"Draft created","content":{"application/json":{"schema":{"type":"object","properties":{"form_id":{"type":"string","format":"uuid","maxLength":36},"share_id":{"type":"string","maxLength":64},"message":{"type":"string","maxLength":2000,"description":"Present only when the source form's node count exceeded the caller's plan limit and was trimmed."}}}}}},"400":{"description":"Invalid request body, or the source form has no forkable nodes","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid credentials","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"workspace_id does not match the caller's credential, or the workspace is at its plan's form limit","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"The source form does not exist or is not published","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/forms/{formId}":{"get":{"operationId":"getForm","tags":["Forms"],"summary":"Get a form","description":"Returns a form and its nodes.","parameters":[{"name":"formId","in":"path","required":true,"schema":{"type":"string","format":"uuid","maxLength":36}}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Form details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FormWithNodes"}}}},"429":{"$ref":"#/components/responses/RateLimited"}}},"patch":{"operationId":"updateForm","tags":["Forms"],"summary":"Update a form","description":"Updates a form.","parameters":[{"name":"formId","in":"path","required":true,"schema":{"type":"string","format":"uuid","maxLength":36}}],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"title":{"type":"string","maxLength":200,"description":"The form's own name (form table)."},"meta_title":{"type":"string","nullable":true,"description":"SEO/social title for search results and link previews (form_metadata.title, surfaced to the viewer as meta_title). Distinct from the form name `title`.","maxLength":2000},"is_live":{"type":"boolean"},"show_step_counter":{"type":"boolean","description":"Show step counter (e.g. '1/5')"},"disable_back_navigation":{"type":"boolean","description":"Prevent respondents from going back"},"total_steps":{"type":"integer","nullable":true,"description":"Override total step count (null = auto-calculate)","format":"int32","minimum":0,"maximum":2147483647},"show_branding":{"type":"boolean","nullable":true,"description":"Per-form override for \"Powered by Clipform\" badge. null = inherit from workspace, true = show, false = hide. Free plans always show branding regardless."},"moderate_responses":{"type":"boolean","nullable":true,"description":"Per-form override for moderating open-ended answers on ingest. null = inherit from workspace, true = moderate, false = do not moderate."},"primary_color":{"type":"string","description":"Primary/brand color (hex or CSS color)","maxLength":20},"background_color":{"type":"string","description":"Background color (hex, rgba, or CSS color)","maxLength":20},"font_family":{"type":"string","description":"Font family name","maxLength":2000},"brand_name":{"type":"string","nullable":true,"description":"Brand name shown alongside the logo in the viewer","maxLength":2000},"logo_url":{"type":"string","nullable":true,"description":"URL to a logo image shown in the viewer header","maxLength":2048},"description":{"type":"string","nullable":true,"description":"SEO description (meta description, og:description)","maxLength":2000},"author":{"type":"string","nullable":true,"description":"Author/brand name shown to respondents","maxLength":2000},"allow_resume":{"type":"boolean","description":"Let returning respondents resume an unfinished session instead of restarting."},"session_expiry_hours":{"type":"integer","minimum":1,"maximum":720,"description":"Hours before a saved resume session expires (clamped 1-720). Default 168 (7 days).","format":"int32"},"results_public":{"type":"boolean","description":"Enable the public results portal. The first enable mints a results_share_id server-side; toggling off and back on keeps the same token."}}}}}},"responses":{"200":{"description":"Form updated","content":{"application/json":{"schema":{"type":"object","properties":{"form_id":{"type":"string","format":"uuid","maxLength":36},"results_share_id":{"type":"string","nullable":true,"description":"Public results portal token, present only when results_public was just enabled for the first time.","maxLength":64}}}}}},"429":{"$ref":"#/components/responses/RateLimited"}}},"delete":{"operationId":"deleteForm","tags":["Forms"],"summary":"Delete a form","description":"Moves a form to the trash and unpublishes it, recoverable via restore.","parameters":[{"name":"formId","in":"path","required":true,"schema":{"type":"string","format":"uuid","maxLength":36}}],"security":[{"bearerAuth":[]}],"responses":{"204":{"description":"Form moved to the trash"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/forms/{formId}/restore":{"post":{"operationId":"restoreForm","tags":["Forms"],"summary":"Restore a form","description":"Restores a trashed form as a draft without republishing it.","parameters":[{"name":"formId","in":"path","required":true,"schema":{"type":"string","format":"uuid","maxLength":36}}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Form restored","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FormSummary"}}}},"403":{"description":"Restoring would exceed the workspace's plan form limit","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/forms/{formId}/permanent":{"delete":{"operationId":"deleteFormPermanently","tags":["Forms"],"summary":"Permanently delete a form","description":"Permanently deletes a form and its nodes, trashed or not.","parameters":[{"name":"formId","in":"path","required":true,"schema":{"type":"string","format":"uuid","maxLength":36}}],"security":[{"bearerAuth":[]}],"responses":{"204":{"description":"Form permanently deleted"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/forms/{formId}/nodes":{"post":{"operationId":"addNode","tags":["Nodes"],"summary":"Add a node","description":"Adds a node to a form.","parameters":[{"name":"formId","in":"path","required":true,"schema":{"type":"string","format":"uuid","maxLength":36}}],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["node"],"properties":{"node":{"$ref":"#/components/schemas/NodeInput"},"after_node_id":{"type":"string","format":"uuid","description":"Insert after this node. Omit to append before end screen. Ignored when auto_arrange is false.","maxLength":36},"auto_arrange":{"type":"boolean","default":true,"description":"When true (default), the new node is wired into the linear logic chain and the canvas is flagged for auto-layout. Set false for manual builder creates so the node lands orphaned (unconnected) and the caller controls its position."}}}}}},"responses":{"201":{"description":"Node added","content":{"application/json":{"schema":{"type":"object","properties":{"node_id":{"type":"string","format":"uuid","maxLength":36},"warnings":{"type":"array","description":"Advisory notices, returned only when present - e.g. inserting a terminal node (end_screen/redirect/link_list/ shopping) via after_node_id truncated the flow there, orphaning whatever was previously downstream.","items":{"type":"string","maxLength":2000},"maxItems":500}}}}}},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/forms/{formId}/nodes/{nodeId}":{"patch":{"operationId":"updateNode","tags":["Nodes"],"summary":"Update a node","description":"Updates a node.","parameters":[{"name":"formId","in":"path","required":true,"schema":{"type":"string","format":"uuid","maxLength":36}},{"name":"nodeId","in":"path","required":true,"schema":{"type":"string","format":"uuid","maxLength":36}}],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"prompt":{"type":"string","maxLength":500},"type":{"$ref":"#/components/schemas/NodeType"},"required":{"type":"boolean"},"public_results_hidden":{"type":"boolean","description":"Hide this node's data from the public results portal without affecting the owner Results tab."},"config":{"type":"object","description":"Type-specific configuration, merged shallowly into the stored config. A null value deletes that key; nested objects are replaced wholesale. When type is changed in the same request, config replaces the stored configuration instead of merging."},"options":{"type":"array","maxItems":100,"items":{"type":"object","required":["content"],"properties":{"id":{"type":"string","format":"uuid","description":"Existing option id to update in place. Omit to insert a new option.","maxLength":36},"content":{"type":"string","maxLength":200},"score":{"type":"number"},"scores":{"type":"object","additionalProperties":{"type":"number"}}}},"description":"Upsert-by-id: the node's options are set to this array. Items with a known id are updated in place (ids preserved), items without one are inserted, and existing options absent from the array are deleted. Order follows array position. Omitting all ids performs a full replace."}}}}}},"responses":{"200":{"description":"Node updated","content":{"application/json":{"schema":{"type":"object","properties":{"node_id":{"type":"string","format":"uuid","maxLength":36},"options":{"type":"array","description":"The node's resulting option set (real ids, in order), returned only when the request updated options. Lets callers reconcile optimistic temp ids without a refetch.","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","maxLength":36},"content":{"type":"string","maxLength":2000},"order":{"type":"integer","format":"int32","minimum":0,"maximum":2147483647},"score":{"type":"number","nullable":true},"scores":{"type":"object","nullable":true,"additionalProperties":{"type":"number"}}}},"maxItems":500},"variables":{"type":"array","description":"The form's full stable variable registry (#4173), returned only when this request's options wrote a scores map - a new category key is auto-registered as a stable row so a conditional branch can route on its id.","items":{"$ref":"#/components/schemas/FormVariable"},"maxItems":200},"warnings":{"type":"array","description":"Advisory notices, returned only when present - e.g. scored options were written to a node whose choice.record_scores is explicitly false.","items":{"type":"string","maxLength":2000},"maxItems":500}}}}}},"429":{"$ref":"#/components/responses/RateLimited"}}},"delete":{"operationId":"deleteNode","tags":["Nodes"],"summary":"Delete a node","description":"Deletes a node and re-links the ones around it.","parameters":[{"name":"formId","in":"path","required":true,"schema":{"type":"string","format":"uuid","maxLength":36}},{"name":"nodeId","in":"path","required":true,"schema":{"type":"string","format":"uuid","maxLength":36}}],"security":[{"bearerAuth":[]}],"responses":{"204":{"description":"Node deleted"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/forms/{formId}/nodes/{nodeId}/media":{"post":{"operationId":"uploadNodeMedia","tags":["node-media"],"summary":"Upload node media","description":"Returns a URL to upload media for a node.","parameters":[{"name":"formId","in":"path","required":true,"schema":{"type":"string","format":"uuid","maxLength":36}},{"name":"nodeId","in":"path","required":true,"schema":{"type":"string","format":"uuid","maxLength":36}}],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["media_type"],"properties":{"media_type":{"type":"string","enum":["video","still"],"description":"Type of media - video (plays) or still (static image/color, optional audio)"},"media_source":{"type":"string","enum":["uploaded","recorded"],"default":"uploaded","description":"How the media was created"},"duration":{"type":"number","description":"Media length in seconds (optional)."},"fit_media":{"type":"boolean","description":"true = contain (show the whole frame), false/omitted = cover (fill the player, croppable, positionable)"}}}}}},"responses":{"200":{"description":"Upload URL created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MediaUploadResponse"}}}},"429":{"$ref":"#/components/responses/RateLimited"}}},"get":{"operationId":"getNodeMedia","tags":["node-media"],"summary":"Get node media","description":"Returns the media attached to a node.","parameters":[{"name":"formId","in":"path","required":true,"schema":{"type":"string","format":"uuid","maxLength":36}},{"name":"nodeId","in":"path","required":true,"schema":{"type":"string","format":"uuid","maxLength":36}}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Media details (or null if no media)","content":{"application/json":{"schema":{"type":"object","properties":{"media":{"$ref":"#/components/schemas/NodeMedia"}}}}}},"429":{"$ref":"#/components/responses/RateLimited"}}},"patch":{"operationId":"updateNodeMedia","tags":["node-media"],"summary":"Update node media","description":"Updates the display properties on a node's media.","parameters":[{"name":"formId","in":"path","required":true,"schema":{"type":"string","format":"uuid","maxLength":36}},{"name":"nodeId","in":"path","required":true,"schema":{"type":"string","format":"uuid","maxLength":36}}],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"position_x":{"type":"number"},"fit_media":{"type":"boolean"},"show_captions":{"type":"boolean"},"options_reveal_seconds":{"type":"number","nullable":true,"description":"Seconds to wait after the video starts before answer options become interactable, where null uses the viewer default and 0 is immediate."}}}}}},"responses":{"200":{"description":"Media updated","content":{"application/json":{"schema":{"type":"object","properties":{"node_id":{"type":"string","format":"uuid","maxLength":36}}}}}},"429":{"$ref":"#/components/responses/RateLimited"}}},"delete":{"operationId":"deleteNodeMedia","tags":["node-media"],"summary":"Delete node media","description":"Removes a node's media.","parameters":[{"name":"formId","in":"path","required":true,"schema":{"type":"string","format":"uuid","maxLength":36}},{"name":"nodeId","in":"path","required":true,"schema":{"type":"string","format":"uuid","maxLength":36}}],"security":[{"bearerAuth":[]}],"responses":{"204":{"description":"Media deleted (idempotent - also 204 when the node had no media)."},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/forms/{formId}/nodes/{nodeId}/media/captions":{"patch":{"operationId":"updateNodeMediaCaptions","tags":["node-media"],"summary":"Update node media captions","description":"Replaces a node's caption words and regroups them into segments.","parameters":[{"name":"formId","in":"path","required":true,"schema":{"type":"string","format":"uuid","maxLength":36}},{"name":"nodeId","in":"path","required":true,"schema":{"type":"string","format":"uuid","maxLength":36}}],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["words"],"properties":{"words":{"type":"array","minItems":1,"maxItems":2000,"items":{"type":"object","required":["word","start","end"],"properties":{"word":{"type":"string","maxLength":2000},"start":{"type":"number","description":"Start time in seconds"},"end":{"type":"number","description":"End time in seconds"}}},"description":"Full edited word-level transcript, in order."}}}}}},"responses":{"200":{"description":"Captions updated","content":{"application/json":{"schema":{"type":"object","properties":{"node_id":{"type":"string","format":"uuid","maxLength":36},"captions":{"type":"array","maxItems":2000,"items":{"type":"object","properties":{"start":{"type":"number"},"end":{"type":"number"},"text":{"type":"string","maxLength":2000},"words":{"type":"array","maxItems":2000,"items":{"type":"object","properties":{"word":{"type":"string","maxLength":2000},"start":{"type":"number"},"end":{"type":"number"}}}}}}}}}}}},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/forms/{formId}/nodes/{nodeId}/media/transcribe":{"post":{"operationId":"retryNodeMediaTranscription","tags":["node-media"],"summary":"Retry node media transcription","description":"Resets a node's video transcription to pending and re-triggers it from the stored media.","parameters":[{"name":"formId","in":"path","required":true,"schema":{"type":"string","format":"uuid","maxLength":36}},{"name":"nodeId","in":"path","required":true,"schema":{"type":"string","format":"uuid","maxLength":36}}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Transcription restarted","content":{"application/json":{"schema":{"type":"object","properties":{"media_id":{"type":"string","format":"uuid","maxLength":36},"transcription_status":{"type":"string","enum":["pending"]}}}}}},"404":{"description":"Node has no video media to transcribe."},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/forms/{formId}/tags":{"put":{"operationId":"setFormTags","tags":["Tags"],"summary":"Set form tags","description":"Replaces a form's tags.","parameters":[{"name":"formId","in":"path","required":true,"schema":{"type":"string","format":"uuid","maxLength":36}}],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["tags"],"properties":{"tags":{"type":"array","items":{"type":"string","maxLength":2000},"description":"Tag names (e.g. [\"quiz\", \"trivia\", \"arsenal\"])","maxItems":500}}}}}},"responses":{"200":{"description":"Tags set","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TagList"}}}},"429":{"$ref":"#/components/responses/RateLimited"}}},"get":{"operationId":"getFormTags","tags":["Tags"],"summary":"List form tags","parameters":[{"name":"formId","in":"path","required":true,"schema":{"type":"string","format":"uuid","maxLength":36}}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Tags","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TagList"}}}},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/forms/{formId}/tags/{tagId}":{"delete":{"operationId":"deleteFormTag","tags":["Tags"],"summary":"Remove a form tag","parameters":[{"name":"formId","in":"path","required":true,"schema":{"type":"string","format":"uuid","maxLength":36}},{"name":"tagId","in":"path","required":true,"schema":{"type":"string","format":"uuid","maxLength":36}}],"security":[{"bearerAuth":[]}],"responses":{"204":{"description":"Tag removed"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/forms/{formId}/links":{"get":{"operationId":"getFormLinks","tags":["tracked-links"],"summary":"List tracked links for a form","description":"Returns a form's tracked share links.","parameters":[{"name":"formId","in":"path","required":true,"schema":{"type":"string","format":"uuid","maxLength":36}}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Tracked links","content":{"application/json":{"schema":{"type":"object","properties":{"links":{"type":"array","items":{"$ref":"#/components/schemas/FormLink"},"maxItems":500}}}}}},"429":{"$ref":"#/components/responses/RateLimited"}}},"post":{"operationId":"createFormLink","tags":["tracked-links"],"summary":"Create a tracked link","description":"Creates a tracked (UTM) share link.","parameters":[{"name":"formId","in":"path","required":true,"schema":{"type":"string","format":"uuid","maxLength":36}}],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["label"],"properties":{"label":{"type":"string","maxLength":100},"utm_source":{"type":"string","nullable":true,"maxLength":2000},"utm_medium":{"type":"string","nullable":true,"maxLength":2000},"utm_campaign":{"type":"string","nullable":true,"maxLength":2000},"utm_term":{"type":"string","nullable":true,"maxLength":2000},"utm_content":{"type":"string","nullable":true,"maxLength":2000}}}}}},"responses":{"201":{"description":"Tracked link created","content":{"application/json":{"schema":{"type":"object","properties":{"link":{"$ref":"#/components/schemas/FormLink"}}}}}},"409":{"description":"A link with that label already exists","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/forms/{formId}/links/{linkId}":{"delete":{"operationId":"deleteFormLink","tags":["tracked-links"],"summary":"Delete a tracked link","parameters":[{"name":"formId","in":"path","required":true,"schema":{"type":"string","format":"uuid","maxLength":36}},{"name":"linkId","in":"path","required":true,"schema":{"type":"string","format":"uuid","maxLength":36}}],"security":[{"bearerAuth":[]}],"responses":{"204":{"description":"Tracked link deleted"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/forms/{formId}/analytics":{"get":{"operationId":"getFormAnalytics","tags":["Analytics"],"summary":"Get form analytics","description":"Returns funnel analytics for a form.","parameters":[{"name":"formId","in":"path","required":true,"schema":{"type":"string","format":"uuid","maxLength":36}},{"name":"start_date","in":"query","schema":{"type":"string","format":"date-time","maxLength":30},"description":"Filter from this date (ISO 8601)"},{"name":"end_date","in":"query","schema":{"type":"string","format":"date-time","maxLength":30},"description":"Filter until this date (ISO 8601)"},{"name":"referrer_url","in":"query","schema":{"type":"string","maxLength":2000},"description":"Filter by referrer. Matches by normalized host and path (scheme, port, query, fragment and a leading www. are ignored); `(direct)` matches sessions with no referrer. Referrer breakdown rows in the response return that same normalized key as their name."},{"name":"country_code","in":"query","schema":{"type":"string","maxLength":2000},"description":"Filter by ISO country code"},{"name":"browser","in":"query","schema":{"type":"string","maxLength":2000},"description":"Filter by browser name"},{"name":"device_type","in":"query","schema":{"type":"string","maxLength":2000},"description":"Filter by device type (desktop, mobile, tablet)"}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Analytics data","content":{"application/json":{"schema":{"type":"object","properties":{"total_views":{"type":"integer","format":"int32","minimum":0,"maximum":2147483647},"total_started":{"type":"integer","format":"int32","minimum":0,"maximum":2147483647},"total_completed":{"type":"integer","format":"int32","minimum":0,"maximum":2147483647},"total_unique_visitors":{"type":"integer","format":"int32","minimum":0,"maximum":2147483647},"views_series":{"type":"array","items":{"type":"object","properties":{"date":{"type":"string","maxLength":2000},"value":{"type":"integer","format":"int32","minimum":0,"maximum":2147483647}}},"maxItems":500},"started_series":{"type":"array","items":{"type":"object"},"maxItems":500},"completed_series":{"type":"array","items":{"type":"object"},"maxItems":500}}}}}},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/forms/{formId}/submissions":{"get":{"operationId":"getFormSubmissions","tags":["Analytics"],"summary":"List submissions","description":"Returns a form's submissions.","parameters":[{"name":"formId","in":"path","required":true,"schema":{"type":"string","format":"uuid","maxLength":36}},{"name":"submission_id","in":"query","schema":{"type":"string","format":"uuid","maxLength":36},"description":"Filter to the response_set with this id (may still return more than one row if it has multiple completed sessions)."}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"List of submissions","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"submission_id":{"type":"string","format":"uuid","maxLength":36,"description":"Stable per-row key: one row per completed session (id = that session's id), or one row for a still-open response_set with no completed session yet (id = the response_set's id).\n"},"response_set_id":{"type":"string","format":"uuid","maxLength":36,"description":"The parent response_set - may repeat across sibling completions of the same set."},"session_id":{"type":"string","format":"uuid","nullable":true,"maxLength":36},"status":{"type":"string","maxLength":2000},"processing_status":{"type":"string","nullable":true,"maxLength":2000,"description":"Back-office processing lifecycle: none/complete (ready), pending/processing (in-flight - answers not yet final), processing_error/failed (released unverified).\n"},"created_at":{"type":"string","format":"date-time","maxLength":30},"completed_at":{"type":"string","format":"date-time","nullable":true,"maxLength":30},"last_activity_at":{"type":"string","format":"date-time","maxLength":30,"description":"When the respondent last made progress (falls back to created_at)"},"total_sessions":{"type":"integer","format":"int32","minimum":0,"maximum":2147483647},"total_responses":{"type":"integer","format":"int32","minimum":0,"maximum":2147483647},"contact_email":{"type":"string","nullable":true,"maxLength":2000},"contact_first_name":{"type":"string","nullable":true,"maxLength":2000},"contact_last_name":{"type":"string","nullable":true,"maxLength":2000},"node_responses":{"type":"object","nullable":true},"locked":{"type":"boolean","description":"True when this response is over the workspace's plan limit. Locked rows have their answer/contact fields nulled.\n"}}},"maxItems":500}}}},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/forms/{formId}/submissions/{submissionId}":{"get":{"operationId":"getSubmissionDetails","tags":["Analytics"],"summary":"Get a submission","description":"Returns one submission in full.","parameters":[{"name":"formId","in":"path","required":true,"schema":{"type":"string","format":"uuid","maxLength":36}},{"name":"submissionId","in":"path","required":true,"schema":{"type":"string","format":"uuid","maxLength":36},"description":"The submission's response_set_id"},{"name":"session_id","in":"query","schema":{"type":"string","format":"uuid","maxLength":36},"description":"Scope the detail to one completed session of this response_set (from list submissions' session_id). Omit for the set-level (in-progress) view."}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Submission details","content":{"application/json":{"schema":{"type":"object"}}}},"403":{"description":"The response is over the workspace's plan limit and locked. Upgrade to view it.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Submission not found for this form","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/forms/{formId}/theme":{"delete":{"operationId":"deleteFormTheme","tags":["Forms"],"summary":"Reset theme to default","description":"Resets a form's theme to defaults.","parameters":[{"name":"formId","in":"path","required":true,"schema":{"type":"string","format":"uuid","maxLength":36}}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Theme reset","content":{"application/json":{"schema":{"type":"object","properties":{"form_id":{"type":"string","format":"uuid","maxLength":36},"theme":{"nullable":true}}}}}},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/forms/{formId}/results":{"get":{"operationId":"getFormResults","tags":["Analytics"],"summary":"Get form results","description":"Returns aggregated results for a form.","parameters":[{"name":"formId","in":"path","required":true,"schema":{"type":"string","format":"uuid","maxLength":36}}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Aggregated results","content":{"application/json":{"schema":{"type":"object","properties":{"total_responses":{"type":"integer","format":"int32","minimum":0,"maximum":2147483647},"public_results_allowed":{"type":"boolean","description":"Whether this workspace may enable the public results portal, server-computed from the rollout flag and allowlist."},"results_url":{"type":"string","format":"uri","description":"Dashboard Responses tab for this form. Absent for an anonymous caller.","maxLength":2048},"nodes":{"type":"array","items":{"type":"object","properties":{"node_id":{"type":"string","maxLength":64},"node_text":{"type":"string","maxLength":2000},"node_type":{"type":"string","maxLength":2000},"total_responses":{"type":"integer","format":"int32","minimum":0,"maximum":2147483647},"total_views":{"type":"integer","format":"int32","minimum":0,"maximum":2147483647},"answers":{"type":"array","items":{"type":"object"},"maxItems":500}}},"maxItems":500},"flow":{"type":"object","properties":{"nodes":{"type":"array","items":{"type":"object"},"maxItems":500},"links":{"type":"array","items":{"type":"object"},"maxItems":500}}}}}}}},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/forms/{formId}/results-share/rotate":{"post":{"operationId":"rotateResultsShare","tags":["Forms"],"summary":"Rotate the public results link","description":"Mints a fresh public results token for a form, invalidating the previous link.","parameters":[{"name":"formId","in":"path","required":true,"schema":{"type":"string","format":"uuid","maxLength":36}}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"New results share token","content":{"application/json":{"schema":{"type":"object","properties":{"form_id":{"type":"string","format":"uuid","maxLength":36},"results_share_id":{"type":"string","description":"24-character lowercase hex token used in the public results URL.","maxLength":64}}}}}},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/forms/{formId}/desktop-handoff":{"post":{"operationId":"desktopHandoff","tags":["Forms"],"summary":"Email a desktop handoff link","description":"Sends the signed-in caller a magic link back into this form's builder for continuing on a computer.","parameters":[{"name":"formId","in":"path","required":true,"schema":{"type":"string","format":"uuid","maxLength":36}}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Handoff email sent","content":{"application/json":{"schema":{"type":"object","properties":{"sent":{"type":"boolean"}}}}}},"400":{"description":"Anonymous session or no email on the account","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/results/public/{resultsShareId}":{"get":{"operationId":"getPublicResults","tags":["Analytics"],"summary":"Get public results","description":"Returns a form's aggregated results for anyone holding its public results link.","security":[],"parameters":[{"name":"resultsShareId","in":"path","required":true,"schema":{"type":"string","description":"24-character lowercase hex public results token.","maxLength":2000}}],"responses":{"200":{"description":"Aggregated results, contact/file/payment nodes and locked responses excluded","content":{"application/json":{"schema":{"type":"object","properties":{"total_responses":{"type":"integer","format":"int32","minimum":0,"maximum":2147483647},"nodes":{"type":"array","items":{"type":"object","properties":{"node_id":{"type":"string","maxLength":64},"node_text":{"type":"string","maxLength":2000},"node_type":{"type":"string","maxLength":2000},"total_responses":{"type":"integer","format":"int32","minimum":0,"maximum":2147483647},"total_views":{"type":"integer","format":"int32","minimum":0,"maximum":2147483647},"answers":{"type":"array","items":{"type":"object"},"maxItems":500}}},"maxItems":500},"flow":{"type":"object"}}}}}},"404":{"description":"Results not found (unknown or rotated token, or the owner has not enabled public results)"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/workspaces/{workspaceId}/dynamic-links":{"get":{"operationId":"listDynamicLinks","tags":["dynamic-links"],"summary":"List dynamic links","description":"Lists a workspace's dynamic links, oldest first, including any orphaned by a deleted form.","parameters":[{"name":"workspaceId","in":"path","required":true,"schema":{"type":"string","format":"uuid","maxLength":36}},{"name":"unattached","in":"query","required":false,"description":"Set to \"true\" to return only unattached (free) links with no form_id; any other value or omission lists all.","schema":{"type":"string","maxLength":10}}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Dynamic links","content":{"application/json":{"schema":{"type":"object","properties":{"dynamic_links":{"type":"array","items":{"$ref":"#/components/schemas/DynamicLink"},"maxItems":500}}}}}},"429":{"$ref":"#/components/responses/RateLimited"}}},"post":{"operationId":"createDynamicLink","tags":["dynamic-links"],"summary":"Create a dynamic link","description":"Creates a dynamic link, either free or pointed at a form in the workspace, minting a repointable public id.","parameters":[{"name":"workspaceId","in":"path","required":true,"schema":{"type":"string","format":"uuid","maxLength":36}}],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name"],"properties":{"name":{"type":"string","maxLength":100},"form_id":{"type":"string","format":"uuid","maxLength":36,"nullable":true}}}}}},"responses":{"201":{"description":"Dynamic link created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DynamicLink"}}}},"400":{"description":"Missing/invalid name, or form_id is not a valid UUID","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The workspace's plan does not include dynamic links","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"form_id does not belong to this workspace","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"A dynamic link with that name already exists","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/workspaces/{workspaceId}/dynamic-links/{publicId}":{"put":{"operationId":"updateDynamicLink","tags":["dynamic-links"],"summary":"Update a dynamic link","description":"Renames, attaches, repoints, or detaches (form_id null) a dynamic link, the primitive for swapping the destination behind a fixed printed URL.","parameters":[{"name":"workspaceId","in":"path","required":true,"schema":{"type":"string","format":"uuid","maxLength":36}},{"name":"publicId","in":"path","required":true,"schema":{"type":"string","maxLength":20}}],"security":[{"bearerAuth":[]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","maxLength":100},"form_id":{"type":"string","format":"uuid","maxLength":36,"nullable":true,"description":"A form id to attach/repoint, or null to detach and leave the link free."},"slug":{"type":"string","nullable":true,"pattern":"^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$","maxLength":63,"description":"Sets the vanity path on the workspace's custom domain, or null to clear it. Rejects a reserved framework/runtime path."}}}}}},"responses":{"200":{"description":"Dynamic link updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DynamicLink"}}}},"400":{"description":"Invalid name/form_id","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Dynamic link (or the target form_id) not found in this workspace","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"A dynamic link with that name already exists","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"$ref":"#/components/responses/RateLimited"}}},"delete":{"operationId":"deleteDynamicLink","tags":["dynamic-links"],"summary":"Delete a dynamic link","description":"Deletes a dynamic link, immediately breaking any printed or embedded URL built from it.","parameters":[{"name":"workspaceId","in":"path","required":true,"schema":{"type":"string","format":"uuid","maxLength":36}},{"name":"publicId","in":"path","required":true,"schema":{"type":"string","maxLength":20}}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Deleted","content":{"application/json":{"schema":{"type":"object","properties":{"deleted":{"type":"boolean"}}}}}},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/dynamic-links/public/{publicId}":{"get":{"operationId":"resolveDynamicLink","tags":["dynamic-links"],"summary":"Resolve a dynamic link","description":"Resolves a dynamic link's public id to the share id of the form it currently points at.","security":[],"parameters":[{"name":"publicId","in":"path","required":true,"schema":{"type":"string","maxLength":20}},{"name":"host","in":"query","required":false,"description":"The custom domain a respondent is viewing the form on; scopes resolution to that domain's workspace.","schema":{"type":"string","maxLength":253}}],"responses":{"200":{"description":"The resolved form","content":{"application/json":{"schema":{"type":"object","properties":{"share_id":{"type":"string","maxLength":2000},"form_id":{"type":"string","format":"uuid","maxLength":36}}}}}},"404":{"description":"Unknown dynamic link, its target form is not live, or the link does not belong to the given host's workspace","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"$ref":"#/components/responses/RateLimited"}}}}},"webhooks":{"form.completed":{"post":{"operationId":"webhookFormCompleted","summary":"Form completed","tags":["Webhooks"],"description":"Sent to your endpoint when a respondent completes a form.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEvent"}}}},"responses":{"2XX":{"description":"Acknowledged. Any 2xx response stops retries."}}}}},"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"API key (cf_*) passed as Bearer token"},"oauth2":{"type":"oauth2","description":"Authorization-code OAuth for installed apps acting on a user's workspace. Access tokens (cf_at_*) are passed as Bearer tokens and authorize the Integrations operations. They are opaque, single-audience, server-side records. Client credentials are issued per app - contact support@clipform.io.","flows":{"authorizationCode":{"authorizationUrl":"https://api.clipform.io/oauth/authorize","tokenUrl":"https://api.clipform.io/oauth/token","refreshUrl":"https://api.clipform.io/oauth/token","scopes":{"forms:read":"Read the workspace's forms.","responses:read":"Read the workspace's form responses.","webhooks:manage":"Subscribe and unsubscribe webhook endpoints."}}}}},"responses":{"RateLimited":{"description":"Rate limit exceeded.","headers":{"Access-Control-Allow-Origin":{"description":"CORS origin permitted to read the response.","schema":{"type":"string","maxLength":2048,"example":"*"}},"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","format":"int32","minimum":0,"maximum":86400},"example":42},"RateLimit-Limit":{"description":"Request quota for the current window.","schema":{"type":"integer","format":"int32","minimum":0,"maximum":1000000},"example":60},"RateLimit-Remaining":{"description":"Requests remaining in the current window.","schema":{"type":"integer","format":"int32","minimum":0,"maximum":1000000},"example":0},"RateLimit-Reset":{"description":"Seconds until the current window resets.","schema":{"type":"integer","format":"int32","minimum":0,"maximum":86400},"example":42}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"schemas":{"WebhookEvent":{"type":"object","description":"Outbound webhook payload. Standard-Webhooks-shaped envelope - the structure is stable and evolves additively within a `version`.","required":["type","version","timestamp","data"],"properties":{"type":{"type":"string","maxLength":1000,"example":"form.completed"},"version":{"type":"string","maxLength":1000,"example":"1"},"timestamp":{"type":"string","format":"date-time","maxLength":30,"example":"2024-01-15T10:30:00Z"},"data":{"type":"object","required":["form_id","form_name","share_id","form_tags","response_id","submitted_at","verified","session","responses"],"properties":{"form_id":{"type":"string","format":"uuid","maxLength":36,"example":"f47ac10b-58cc-4372-a567-0e02b2c3d479"},"form_name":{"type":"string","maxLength":1000,"example":"Customer Feedback"},"share_id":{"type":"string","maxLength":1000,"example":"abc12345"},"form_tags":{"type":"array","items":{"type":"string","maxLength":1000},"maxItems":20},"response_id":{"type":"string","format":"uuid","maxLength":36,"example":"550e8400-e29b-41d4-a716-446655440000"},"submitted_at":{"type":"string","format":"date-time","maxLength":30,"example":"2024-01-15T10:30:00Z"},"verified":{"type":"boolean","example":true,"description":"Whether the submission's back-office processing finished without a terminal failure. `false` means it was released after a persistent processing error - its answers are still delivered so nothing is lost, but may be incomplete (e.g. a missing transcript or moderation verdict), so treat them as unverified."},"session":{"type":"object","properties":{"device":{"type":"string","maxLength":1000,"example":"desktop"},"browser":{"type":"string","maxLength":1000,"example":"Chrome"},"country":{"type":"string","maxLength":1000,"example":"United States"},"city":{"type":"string","maxLength":1000,"example":"San Francisco"},"time_spent_seconds":{"type":"integer","format":"int32","minimum":0,"maximum":2147483647,"nullable":true,"example":45}}},"responses":{"type":"array","description":"The submission's answers, one item per answered node.","maxItems":500,"items":{"oneOf":[{"$ref":"#/components/schemas/WebhookResponseChoice"},{"$ref":"#/components/schemas/WebhookResponseOpen"},{"$ref":"#/components/schemas/WebhookResponseDetails"},{"$ref":"#/components/schemas/WebhookResponseDraw"},{"$ref":"#/components/schemas/WebhookResponseFile_upload"},{"$ref":"#/components/schemas/WebhookResponsePayment"},{"$ref":"#/components/schemas/WebhookResponseFile_download"},{"$ref":"#/components/schemas/WebhookResponseCamera"}],"discriminator":{"propertyName":"node_type","mapping":{"choice":"#/components/schemas/WebhookResponseChoice","button":"#/components/schemas/WebhookResponseChoice","open":"#/components/schemas/WebhookResponseOpen","details":"#/components/schemas/WebhookResponseDetails","draw":"#/components/schemas/WebhookResponseDraw","file_upload":"#/components/schemas/WebhookResponseFile_upload","payment":"#/components/schemas/WebhookResponsePayment","file_download":"#/components/schemas/WebhookResponseFile_download","camera":"#/components/schemas/WebhookResponseCamera"}}}}}}},"example":{"type":"form.completed","version":"1","timestamp":"2024-01-15T10:30:00Z","data":{"form_id":"f47ac10b-58cc-4372-a567-0e02b2c3d479","form_name":"Customer Feedback","share_id":"abc12345","form_tags":["sales","vip"],"response_id":"550e8400-e29b-41d4-a716-446655440000","submitted_at":"2024-01-15T10:30:00Z","verified":true,"session":{"device":"desktop","browser":"Chrome","country":"United States","city":"San Francisco","time_spent_seconds":45},"responses":[{"node_id":"3fa85f64-5717-4562-b3fc-2c963f66afa6","node_type":"choice","prompt":"How did you hear about us?","label":"Option A","option_id":"opt-789"},{"node_id":"3fa85f64-5717-4562-b3fc-2c963f66afa6","node_type":"open","prompt":"How did you hear about us?","text":"I loved it"},{"node_id":"3fa85f64-5717-4562-b3fc-2c963f66afa6","node_type":"details","prompt":"How did you hear about us?","fields":[{"type":"email","value":"jane@example.com"},{"type":"name","value":"Jane Doe"}],"consent":[{"name":"terms","accepted":true,"type":"consent","label":"I agree to the terms of service and privacy policy."},{"name":"nda","accepted":true,"type":"consent","label":"I agree to the mutual non-disclosure agreement.","reached_end":true,"document_version":"2026-01-10T09:00:00.000Z","accepted_at":"2026-01-15T10:30:00Z","document":{"url":"https://example.com/consent/nda.pdf","filename":"nda.pdf"}},{"name":"marketing","accepted":false,"type":"opt_in","label":"Send me product updates and marketing emails."}]},{"node_id":"3fa85f64-5717-4562-b3fc-2c963f66afa6","node_type":"draw","prompt":"How did you hear about us?","media":{"type":"image","content_type":"image/png","filename":"drawing.png","url":"https://project-ref.supabase.co/storage/v1/object/sign/media-responses/path/to/file?token=example-token","download_url":"https://project-ref.supabase.co/storage/v1/object/sign/media-responses/path/to/file?token=example-token&download=drawing.png","expires_at":"2024-01-15T12:30:00Z"}},{"node_id":"3fa85f64-5717-4562-b3fc-2c963f66afa6","node_type":"file_upload","prompt":"How did you hear about us?","files":[{"id":"6f4b2c1e-0d3a-4a2b-9c8d-1e2f3a4b5c6d","filename":"report.pdf","content_type":"application/pdf","size":102400,"uploaded_at":"2024-01-15T10:29:00Z","url":"https://project-ref.supabase.co/storage/v1/object/sign/media-responses/path/to/file?token=example-token","download_url":"https://project-ref.supabase.co/storage/v1/object/sign/media-responses/path/to/file?token=example-token&download=report.pdf","expires_at":"2024-01-15T12:30:00Z"}]},{"node_id":"3fa85f64-5717-4562-b3fc-2c963f66afa6","node_type":"payment","prompt":"How did you hear about us?","provider":"stripe","status":"succeeded","amount":5000,"currency":"usd","payment_intent_id":"pi_3QexampleSampleIntent00","charge_id":"ch_3QexampleSampleCharge00","receipt_url":"https://pay.stripe.com/receipts/payment/sample-receipt","receipt_number":"1234-5678","customer":{"name":"Jane Doe","email":"jane@example.com","phone":"+15551234567","address":{"line1":"123 Market St","city":"San Francisco","state":"CA","postal_code":"94103","country":"US"}}},{"node_id":"3fa85f64-5717-4562-b3fc-2c963f66afa6","node_type":"file_download","prompt":"How did you hear about us?","files":[{"filename":"brochure.pdf","content_type":"application/pdf","downloaded_at":"2024-01-15T10:29:00Z","url":"https://project-ref.supabase.co/storage/v1/object/sign/file-downloads/path/to/file?token=example-token","download_url":"https://project-ref.supabase.co/storage/v1/object/sign/file-downloads/path/to/file?token=example-token&download=brochure.pdf","expires_at":"2024-01-15T12:30:00Z"}]},{"node_id":"3fa85f64-5717-4562-b3fc-2c963f66afa6","node_type":"camera","prompt":"How did you hear about us?","files":[{"id":"6f4b2c1e-0d3a-4a2b-9c8d-1e2f3a4b5c6d","filename":"photo.jpg","content_type":"image/jpeg","size":512000,"uploaded_at":"2024-01-15T10:29:00Z","url":"https://project-ref.supabase.co/storage/v1/object/sign/respondent-captures/path/to/file?token=example-token","download_url":"https://project-ref.supabase.co/storage/v1/object/sign/respondent-captures/path/to/file?token=example-token&download=photo.jpg","expires_at":"2024-01-15T12:30:00Z"}]}]}}},"WebhookResponseBase":{"type":"object","required":["node_id","prompt","node_type"],"properties":{"node_id":{"type":"string","format":"uuid","maxLength":36,"example":"3fa85f64-5717-4562-b3fc-2c963f66afa6"},"prompt":{"type":"string","maxLength":1000,"example":"How did you hear about us?"},"node_type":{"type":"string","maxLength":1000,"example":"choice","description":"The kind of node this answer came from (`choice`, `button`, `open`, `details`, ...). Discriminates the value fields below. Unknown or future types always include `node_id`, `prompt`, and `node_type`, so they can be handled generically."}}},"WebhookResponseChoice":{"title":"Choice or button answer","allOf":[{"$ref":"#/components/schemas/WebhookResponseBase"},{"type":"object","properties":{"node_type":{"type":"string","enum":["choice","button"]},"label":{"type":"string","maxLength":1000,"example":"Option A","description":"The chosen option's text."},"option_id":{"type":"string","maxLength":1000,"example":"opt-789","description":"The chosen option's id."}}}]},"WebhookResponseOpen":{"title":"Open-ended answer","allOf":[{"$ref":"#/components/schemas/WebhookResponseBase"},{"type":"object","properties":{"node_type":{"type":"string","enum":["open"]},"text":{"type":"string","maxLength":1000,"example":"I loved it","description":"The respondent's typed answer."},"media":{"type":"object","properties":{"type":{"type":"string","maxLength":1000,"example":"video","description":"`audio` or `video`."},"content_type":{"type":"string","maxLength":1000,"example":"video/mp4","description":"MIME type of the recording."},"filename":{"type":"string","maxLength":1000,"example":"answer.mp4","description":"Suggested download filename."},"url":{"type":"string","format":"uri","maxLength":2048,"example":"https://project-ref.supabase.co/storage/v1/object/sign/media-responses/path/to/file?token=example-token","description":"Signed link to fetch or stream the file inline."},"download_url":{"type":"string","format":"uri","maxLength":2048,"example":"https://project-ref.supabase.co/storage/v1/object/sign/media-responses/path/to/file?token=example-token&download=answer.mp4","description":"Same link forced to download."},"expires_at":{"type":"string","format":"date-time","maxLength":30,"example":"2024-01-15T12:30:00Z","description":"When the links stop working."}},"description":"Present for audio/video answers. `url` is a direct, time-limited signed link to the recording - valid for about 48 hours and supporting HTTP range requests, so it can be fetched or streamed straight into another tool - and `download_url` is the same link forced to download (Content-Disposition: attachment). After they expire, re-fetch the submission from the authenticated API (using the stable `response_id`) for fresh links."},"transcription":{"type":"object","properties":{"text":{"type":"string","maxLength":1000,"example":"I loved it","description":"The full transcript."},"language":{"type":"string","maxLength":1000,"example":"en","description":"BCP-47 language code, when detected."},"segments":{"type":"array","items":{"type":"object","properties":{"start":{"type":"number","nullable":true},"end":{"type":"number","nullable":true},"text":{"type":"string","maxLength":1000}}},"maxItems":2000,"description":"Timestamped transcript segments (start/end in seconds) for captions or seeking. Present when word-level timing is available."}},"description":"Present when the audio/video answer was transcribed."}}}]},"WebhookResponseDetails":{"title":"Details answer","allOf":[{"$ref":"#/components/schemas/WebhookResponseBase"},{"type":"object","properties":{"node_type":{"type":"string","enum":["details"]},"fields":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string","maxLength":1000},"value":{"type":"string","maxLength":1000}}},"maxItems":50,"description":"The contact details the respondent filled in. Each entry's `type` is the field kind (e.g. `email`, `first_name`), not the node type. Only filled fields appear."},"consent":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string","maxLength":1000,"description":"The consent item's field key."},"accepted":{"type":"boolean","description":"Whether the respondent accepted this agreement."},"type":{"type":"string","maxLength":1000,"description":"`consent` (required) or `opt_in` (optional)."},"label":{"type":"string","maxLength":1000,"description":"The exact agreement wording, snapshotted at submission."},"reached_end":{"type":"boolean","description":"Whether the respondent scrolled the attached document to the end. Present only for document-gated agreements."},"document_version":{"type":"string","maxLength":1000,"description":"The exact version of the attached agreement document the respondent saw. Present only for document-gated agreements."},"accepted_at":{"type":"string","maxLength":1000,"description":"ISO timestamp of when the respondent accepted the document-gated agreement. Present only for document-gated agreements."},"document":{"type":"object","properties":{"url":{"type":"string","format":"uri","maxLength":2048,"description":"Link to the agreement file."},"filename":{"type":"string","maxLength":1000,"description":"The agreement file's name."}},"description":"The exact agreement file the respondent accepted, stamped when they submitted. Present only for document-gated agreements whose file still matched the version they saw."}}},"maxItems":200,"description":"Consent and opt-in agreements the respondent was shown, present only when the node has them. `accepted` records their choice and `label` is the exact wording they agreed to, snapshotted at submission - editing the agreement text later does not rewrite past responses."}}}]},"WebhookResponseDraw":{"title":"Drawing answer","allOf":[{"$ref":"#/components/schemas/WebhookResponseBase"},{"type":"object","properties":{"node_type":{"type":"string","enum":["draw"]},"media":{"type":"object","properties":{"type":{"type":"string","maxLength":1000,"example":"image","description":"Always `image`."},"content_type":{"type":"string","maxLength":1000,"example":"image/png","description":"Image MIME type."},"filename":{"type":"string","maxLength":1000,"example":"drawing.png","description":"Suggested download filename."},"url":{"type":"string","format":"uri","maxLength":2048,"example":"https://project-ref.supabase.co/storage/v1/object/sign/media-responses/path/to/file?token=example-token","description":"Signed link to fetch the image inline."},"download_url":{"type":"string","format":"uri","maxLength":2048,"example":"https://project-ref.supabase.co/storage/v1/object/sign/media-responses/path/to/file?token=example-token&download=drawing.png","description":"Same link forced to download."},"expires_at":{"type":"string","format":"date-time","maxLength":30,"example":"2024-01-15T12:30:00Z","description":"When the links stop working."}},"description":"The respondent's drawing, exported as a PNG image. `url` is a direct, time-limited signed link (~48h, HTTP range) and `download_url` is the same link forced to download. Re-fetch from the authenticated API after they expire."},"game":{"type":"object","properties":{"score":{"type":"integer","format":"int32","minimum":0,"maximum":2147483647,"nullable":true,"example":82,"description":"0-100 match score against the target outline."},"avg_deviation":{"type":"number","nullable":true,"example":0.08,"description":"Average normalized deviation from the target outline (lower is better)."},"tier":{"type":"string","maxLength":1000,"example":"Great match","description":"The configured tier label the score falls into."}},"description":"Present only when the node has a configured target shape - the respondent's score against it."}}}]},"WebhookResponseFile_upload":{"title":"File upload answer","allOf":[{"$ref":"#/components/schemas/WebhookResponseBase"},{"type":"object","properties":{"node_type":{"type":"string","enum":["file_upload"]},"files":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","maxLength":36},"filename":{"type":"string","maxLength":1000},"content_type":{"type":"string","maxLength":1000},"size":{"type":"integer","format":"int32","minimum":0,"maximum":2147483647,"nullable":true},"uploaded_at":{"type":"string","format":"date-time","maxLength":30},"url":{"type":"string","format":"uri","maxLength":2048},"download_url":{"type":"string","format":"uri","maxLength":2048},"expires_at":{"type":"string","format":"date-time","maxLength":30}}},"maxItems":20,"description":"The uploaded files. Each has a direct, time-limited signed `url` (~48h, HTTP range) and a `download_url` (same link forced to download). Re-fetch from the authenticated API after they expire."}}}]},"WebhookResponsePayment":{"title":"Payment answer","allOf":[{"$ref":"#/components/schemas/WebhookResponseBase"},{"type":"object","properties":{"node_type":{"type":"string","enum":["payment"]},"provider":{"type":"string","maxLength":1000,"description":"Payment provider that processed the charge (currently always `stripe`)."},"status":{"type":"string","maxLength":1000,"description":"Payment status: `succeeded`, `partially_refunded`, or `refunded` - reflects Stripe at the time the event fired. A refund after delivery does not re-fire the webhook - see the Stripe integration docs."},"amount":{"type":"integer","format":"int32","minimum":0,"maximum":2147483647,"nullable":true,"description":"Amount charged, in the currency's smallest unit (e.g. 5000 = $50.00)."},"amount_refunded":{"type":"integer","format":"int32","minimum":0,"maximum":2147483647,"nullable":true,"description":"Amount refunded so far, in the currency's smallest unit. Only present once a refund (full or partial) has been issued."},"currency":{"type":"string","maxLength":1000,"description":"Three-letter ISO currency code, lowercase."},"payment_intent_id":{"type":"string","maxLength":1000,"description":"Stripe PaymentIntent ID (`pi_...`)."},"charge_id":{"type":"string","maxLength":1000,"description":"Stripe Charge ID (`ch_...`) for reconciliation against your Stripe dashboard."},"receipt_url":{"type":"string","maxLength":1000,"description":"Stripe-hosted receipt page for this charge."},"receipt_number":{"type":"string","maxLength":1000,"description":"Stripe receipt number - present once Stripe emails a receipt."},"customer":{"type":"object","properties":{"name":{"type":"string","maxLength":1000},"email":{"type":"string","maxLength":1000},"phone":{"type":"string","maxLength":1000},"address":{"type":"object","properties":{"line1":{"type":"string","maxLength":1000},"line2":{"type":"string","maxLength":1000},"city":{"type":"string","maxLength":1000},"state":{"type":"string","maxLength":1000},"postal_code":{"type":"string","maxLength":1000},"country":{"type":"string","maxLength":1000}},"description":"Billing address. Only non-null parts are present."}},"description":"Billing details the respondent entered at checkout. Only non-null parts are present."}}}]},"WebhookResponseFile_download":{"title":"File download answer","allOf":[{"$ref":"#/components/schemas/WebhookResponseBase"},{"type":"object","properties":{"node_type":{"type":"string","enum":["file_download"]},"files":{"type":"array","items":{"type":"object","properties":{"filename":{"type":"string","maxLength":1000},"content_type":{"type":"string","maxLength":1000},"downloaded_at":{"type":"string","format":"date-time","maxLength":30},"url":{"type":"string","format":"uri","maxLength":2048},"download_url":{"type":"string","format":"uri","maxLength":2048},"expires_at":{"type":"string","format":"date-time","maxLength":30}}},"maxItems":20,"description":"The files the respondent downloaded. Each has a direct, time-limited signed `url` (~48h, HTTP range) and a `download_url` (same link forced to download). Re-fetch from the authenticated API after they expire."}}}]},"WebhookResponseCamera":{"title":"Camera answer","allOf":[{"$ref":"#/components/schemas/WebhookResponseBase"},{"type":"object","properties":{"node_type":{"type":"string","enum":["camera"]},"files":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","maxLength":36},"filename":{"type":"string","maxLength":1000},"content_type":{"type":"string","maxLength":1000},"size":{"type":"integer","format":"int32","minimum":0,"maximum":2147483647,"nullable":true},"uploaded_at":{"type":"string","format":"date-time","maxLength":30},"url":{"type":"string","format":"uri","maxLength":2048},"download_url":{"type":"string","format":"uri","maxLength":2048},"expires_at":{"type":"string","format":"date-time","maxLength":30}}},"maxItems":20,"description":"The captured photo or video, as a single-item array mirroring file_upload's shape. Has a direct, time-limited signed `url` (~48h, HTTP range) and a `download_url` (same link forced to download). Re-fetch from the authenticated API after they expire."}}}]},"Error":{"type":"object","description":"Standard error envelope returned by every failed request.","required":["code","error"],"properties":{"code":{"type":"string","description":"Machine-readable error code. Keep in lockstep with the ErrorCode union in apps/api/src/lib/errors.ts (source of truth).","enum":["VALIDATION_ERROR","UNKNOWN_SESSION","RATE_LIMITED","UNAUTHORIZED","FORBIDDEN","NOT_FOUND","INTERNAL_ERROR","RENDER_FAILED","PAYMENT_ERROR","PLAN_LIMIT","RESPONSE_LIMIT","CONFLICT"]},"error":{"type":"string","description":"Human-readable error message.","maxLength":2000},"details":{"description":"Optional structured detail; present on some validation errors."}}},"TagList":{"type":"object","properties":{"tags":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","maxLength":36},"name":{"type":"string","maxLength":2000},"color":{"type":"string","maxLength":20}}},"maxItems":500}}},"FormLink":{"type":"object","properties":{"id":{"type":"string","format":"uuid","maxLength":36},"form_id":{"type":"string","format":"uuid","maxLength":36},"label":{"type":"string","maxLength":2000},"utm_source":{"type":"string","nullable":true,"maxLength":2000},"utm_medium":{"type":"string","nullable":true,"maxLength":2000},"utm_campaign":{"type":"string","nullable":true,"maxLength":2000},"utm_term":{"type":"string","nullable":true,"maxLength":2000},"utm_content":{"type":"string","nullable":true,"maxLength":2000},"created_at":{"type":"string","format":"date-time","maxLength":30}}},"DynamicLink":{"type":"object","properties":{"id":{"type":"string","format":"uuid","maxLength":36},"public_id":{"type":"string","description":"Opaque 8-character hex handle, repointable to a different form_id without changing this value.","maxLength":20},"name":{"type":"string","maxLength":100},"form_id":{"type":"string","format":"uuid","nullable":true,"description":"Null when the target form has been deleted (an orphaned link, still listed and repointable).","maxLength":36},"slug":{"type":"string","nullable":true,"pattern":"^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$","maxLength":63,"description":"Vanity path on the workspace's active custom domain (forms.acme.com/<slug>). Null until set."},"form":{"type":"object","nullable":true,"description":"Present in list responses only.","properties":{"share_id":{"type":"string","nullable":true,"maxLength":2000},"title":{"type":"string","nullable":true,"maxLength":2000}}},"created_at":{"type":"string","format":"date-time","maxLength":30},"updated_at":{"type":"string","format":"date-time","maxLength":30}}},"NodeType":{"type":"string","enum":["choice","open","button","details","payment","file_download","redirect","end_screen"]},"NodeInput":{"type":"object","required":["type","prompt"],"properties":{"id":{"type":"string","format":"uuid","description":"Optional client-generated node id (RF-style stable identity). When provided the node is inserted with this id so the builder's optimistic node needs no temp-id swap. Omit to let the server generate one.","maxLength":36},"type":{"$ref":"#/components/schemas/NodeType"},"prompt":{"type":"string","maxLength":500,"description":"The text shown to the respondent"},"label":{"type":"string","description":"Internal short label used in exports and reports (defaults to prompt)","maxLength":2000},"required":{"type":"boolean","default":true},"config":{"type":"object","description":"Type-specific configuration. Key options by type:\n- choice: { choice, selection_mode, allow_text_response, randomise_options, show_option_count, option_display, content_media_type }\n- open: { formats, content_media_type, max_recording_seconds }\n- button: { button_text, button_style }\n- details: { title, fields, description, consent_items }\n- payment: { amount, currency, provider, workspace_integration_id, title, description }\n- file_download: { files, button_text, description }\n- redirect: { url, auto_redirect }\n- end_screen: { title, message, show_score, icon, show_share_button, cta_type, cta_text, cta_url, score_ranges, scoring_results }\n"},"options":{"type":"array","maxItems":100,"items":{"type":"object","required":["content"],"properties":{"id":{"type":"string","format":"uuid","description":"Client-generated option id (optional). When provided it's used as the row id so the builder's optimistic option is the persisted row (no temp id swap). Omit to let the server generate one.","maxLength":36},"content":{"type":"string","maxLength":200},"score":{"type":"integer","nullable":true,"description":"Points awarded when this option is selected. Use `scores` instead to score across multiple named categories.","format":"int32","minimum":0,"maximum":2147483647},"scores":{"type":"object","additionalProperties":{"type":"integer","format":"int32","minimum":0,"maximum":2147483647},"nullable":true,"description":"Per-category scoring map. Keys are category names, values are points. -1 = knockout."}}},"description":"Answer options for choice/button nodes"}}},"Node":{"type":"object","properties":{"id":{"type":"string","format":"uuid","maxLength":36},"type":{"$ref":"#/components/schemas/NodeType"},"prompt":{"type":"string","maxLength":2000},"label":{"type":"string","maxLength":2000},"required":{"type":"boolean"},"config":{"type":"object"},"options":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","maxLength":36},"content":{"type":"string","maxLength":2000},"order":{"type":"integer","format":"int32","minimum":0,"maximum":2147483647},"score":{"type":"integer","nullable":true,"description":"Single-category point value (simple quiz scoring)","format":"int32","minimum":0,"maximum":2147483647},"scores":{"type":"object","additionalProperties":{"type":"integer","format":"int32","minimum":0,"maximum":2147483647},"nullable":true,"description":"Per-category scoring map (multi-outcome quizzes)"}}},"maxItems":500},"media_id":{"type":"string","format":"uuid","nullable":true,"description":"Linked node_media row id (returned in builder views - include=canvas/logic/media)","maxLength":36}}},"MediaUploadResponse":{"type":"object","properties":{"media_id":{"type":"string","format":"uuid","maxLength":36},"upload_url":{"type":"string","format":"uri","description":"The URL to upload the file to.","maxLength":2048},"upload_method":{"type":"string","enum":["tus","put"],"description":"How to send the file: \"tus\" = resumable upload (the tus.io protocol, used for video), \"put\" = a single PUT request (used for images)."},"status":{"type":"string","enum":["awaiting_upload"]}}},"NodeMedia":{"type":"object","nullable":true,"properties":{"id":{"type":"string","format":"uuid","maxLength":36},"media_type":{"type":"string","enum":["video","still"]},"media_source":{"type":"string","enum":["uploaded","recorded"]},"status":{"type":"string","enum":["ready","processing","errored"]},"playback_id":{"type":"string","nullable":true,"description":"Playback ID (video only)","maxLength":64},"storage_path":{"type":"string","nullable":true,"description":"Stored file path (image only)","maxLength":2000},"background_color":{"type":"string","nullable":true,"description":"CSS color/gradient (still color)","maxLength":20},"audio_storage_path":{"type":"string","nullable":true,"description":"Optional audio for stills (auto-plays, no controls)","maxLength":2000},"duration":{"type":"integer","nullable":true,"description":"Video duration in seconds","format":"int32","minimum":0,"maximum":2147483647},"video_width":{"type":"integer","nullable":true,"format":"int32","minimum":0,"maximum":2147483647},"video_height":{"type":"integer","nullable":true,"format":"int32","minimum":0,"maximum":2147483647},"options_reveal_seconds":{"type":"number","nullable":true,"description":"Seconds to wait after video starts before answer options appear (null = viewer default 3s, 0 = immediate)"},"transcription_status":{"type":"string","enum":["pending","processing","completed","failed","skipped"]},"created_at":{"type":"string","format":"date-time","maxLength":30}}},"FormSummary":{"type":"object","properties":{"id":{"type":"string","format":"uuid","maxLength":36},"title":{"type":"string","maxLength":2000},"share_id":{"type":"string","maxLength":64},"is_live":{"type":"boolean"},"has_unpublished_changes":{"type":"boolean","description":"True when the working copy has drifted from the published snapshot."},"created_at":{"type":"string","format":"date-time","maxLength":30},"updated_at":{"type":"string","format":"date-time","maxLength":30},"deleted_at":{"type":"string","format":"date-time","nullable":true,"description":"When the form was moved to the trash. Null for an active form.","maxLength":30},"tags":{"type":"array","description":"Only present when `?include=tags` is passed.","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","maxLength":36},"name":{"type":"string","maxLength":2000},"color":{"type":"string","nullable":true,"maxLength":20}}},"maxItems":500},"builder_url":{"type":"string","format":"uri","description":"Dashboard Build tab for this form. Absent for an anonymous caller.","maxLength":2048},"viewer_url":{"type":"string","format":"uri","description":"Live respondent link. Present only for a published (is_live) form, and absent for an anonymous caller.","maxLength":2048}}},"FormList":{"type":"object","properties":{"forms":{"type":"array","items":{"$ref":"#/components/schemas/FormSummary"},"maxItems":500},"next_cursor":{"type":"string","nullable":true,"description":"Opaque cursor for the next page. Null when there are no more results.","maxLength":2000}}},"ContentMedia":{"type":"object","properties":{"url":{"type":"string","format":"uri","maxLength":2048},"thumbUrl":{"type":"string","format":"uri","nullable":true,"maxLength":2048},"width":{"type":"integer","format":"int32","minimum":0,"maximum":2147483647},"height":{"type":"integer","format":"int32","minimum":0,"maximum":2147483647},"title":{"type":"string","nullable":true,"maxLength":2000},"attribution":{"type":"string","maxLength":2000},"license":{"type":"string","maxLength":2000},"source":{"type":"string","description":"Provider name (e.g. Pexels, Unsplash)","maxLength":2000},"sourceUrl":{"type":"string","format":"uri","maxLength":2048}}},"ContentNewsItem":{"type":"object","properties":{"title":{"type":"string","maxLength":2000},"description":{"type":"string","nullable":true,"maxLength":2000},"source":{"type":"string","maxLength":2000},"author":{"type":"string","nullable":true,"maxLength":2000},"url":{"type":"string","format":"uri","maxLength":2048},"imageUrl":{"type":"string","format":"uri","nullable":true,"maxLength":2048},"publishedAt":{"type":"string","maxLength":2000}}},"ContentMusic":{"type":"object","properties":{"id":{"type":"string","maxLength":64},"name":{"type":"string","maxLength":2000},"duration":{"type":"number","description":"Duration in seconds"},"artistName":{"type":"string","maxLength":2000},"audioUrl":{"type":"string","format":"uri","maxLength":2048},"downloadUrl":{"type":"string","format":"uri","nullable":true,"maxLength":2048},"tags":{"type":"array","items":{"type":"string","maxLength":2000},"maxItems":500},"instrumental":{"type":"boolean"},"license":{"type":"string","maxLength":2000},"source":{"type":"string","maxLength":2000},"sourceUrl":{"type":"string","format":"uri","maxLength":2048}}},"TtsResponse":{"type":"object","properties":{"audio_url":{"type":"string","format":"uri","description":"Public URL to the generated audio file","maxLength":2048},"storage_path":{"type":"string","description":"Stored file path","maxLength":2000},"captions":{"type":"array","items":{"type":"object","properties":{"word":{"type":"string","maxLength":2000},"start":{"type":"number","description":"Start time in seconds"},"end":{"type":"number","description":"End time in seconds"}}},"description":"Word-level timing data for caption sync","maxItems":500},"voice":{"type":"string","maxLength":2000}}},"RenderResponse":{"type":"object","properties":{"storage_path":{"type":"string","description":"Stored file path","maxLength":2000},"public_url":{"type":"string","format":"uri","maxLength":2048},"format":{"type":"string","enum":["mp4","png"]},"cache_hit":{"type":"boolean","description":"True when the render was served from the render cache (identical composition + props rendered before)"}}},"Composition":{"type":"object","properties":{"id":{"type":"string","description":"Composition ID for use with POST /creative/render","maxLength":64},"description":{"type":"string","maxLength":2000},"width":{"type":"integer","format":"int32","minimum":0,"maximum":2147483647},"height":{"type":"integer","format":"int32","minimum":0,"maximum":2147483647},"fps":{"type":"integer","format":"int32","minimum":0,"maximum":2147483647},"durationInFrames":{"type":"integer","format":"int32","minimum":0,"maximum":2147483647},"props":{"type":"object","description":"Input props schema"}}},"FormVariable":{"type":"object","description":"One row of a form's stable variable registry (#4173) - a category or custom scoring variable a conditional branch can route on by its stable id instead of a mutable name. Built-in variables (score, max_score) are reserved keys resolved specially and never appear here.","properties":{"id":{"type":"string","format":"uuid","maxLength":36},"key":{"type":"string","description":"Immutable internal identifier, frozen at creation. Never rewritten - a rename only edits `label`.","maxLength":200},"label":{"type":"string","description":"Editable display name.","maxLength":200},"type":{"type":"string","enum":["number","text"]},"kind":{"type":"string","enum":["builtin","category","custom"]}}},"FormWithNodes":{"type":"object","properties":{"form_id":{"type":"string","format":"uuid","maxLength":36},"title":{"type":"string","maxLength":2000},"is_live":{"type":"boolean","description":"Whether the form is online for respondents (separate from publish state)."},"has_unpublished_changes":{"type":"boolean","description":"True when the live working copy has drifted from the published snapshot respondents currently see. Cleared by publishing (sending `is_live: true`, which re-freezes the snapshot)."},"published_version_id":{"type":"string","format":"uuid","nullable":true,"description":"The currently published form_version, or null if never published.","maxLength":36},"nodes":{"type":"array","items":{"$ref":"#/components/schemas/Node"},"maxItems":500},"variables":{"type":"array","description":"The form's stable variable registry (#4173) - category/custom scoring variables a conditional branch can route on by id. Built-ins (score, max_score) are reserved keys, not rows here. Present only with `include=logic`.","items":{"$ref":"#/components/schemas/FormVariable"},"maxItems":200},"urls":{"type":"object","description":"Dashboard/viewer deeplinks for this form (#3405). An anonymous caller gets only `viewer` (a live link, or a scoped preview link for a draft); a non-anonymous caller gets every dashboard tab plus `viewer` when the form is live.","properties":{"viewer":{"type":"string","format":"uri","description":"Live respondent link, or a scoped preview link for an anonymous caller's draft.","maxLength":2048},"builder":{"type":"string","format":"uri","description":"Build tab - the node/canvas editor.","maxLength":2048},"summary":{"type":"string","format":"uri","description":"Summary tab - form overview and key stats.","maxLength":2048},"responses":{"type":"string","format":"uri","description":"Responses tab - individual submissions.","maxLength":2048},"analytics":{"type":"string","format":"uri","description":"Analytics tab - views, starts, completion rate, drop-off per node.","maxLength":2048},"share":{"type":"string","format":"uri","description":"Share tab - link, QR, social.","maxLength":2048},"embed":{"type":"string","format":"uri","description":"Embed setup for websites.","maxLength":2048},"dynamic_link":{"type":"string","format":"uri","description":"Dynamic/personalized link setup.","maxLength":2048}}}}}}}}