Skip to content

feat(jotform): trigger a workflow on every new form submission - #6802

Merged
waleedlatif1 merged 3 commits into
stagingfrom
feat/jotform-trigger
Aug 18, 2026
Merged

feat(jotform): trigger a workflow on every new form submission#6802
waleedlatif1 merged 3 commits into
stagingfrom
feat/jotform-trigger

Conversation

@waleedlatif1

Copy link
Copy Markdown
Collaborator

Summary

  • Adds a jotform_webhook trigger — new submission is Jotform's only webhook event — wired into the Jotform block, trigger registry, and provider registry
  • Deploying registers the callback on the form through the Jotform API; undeploying removes it
  • Teaches the shared webhook body parser to read multipart/form-data. Jotform posts submissions that way, and parseWebhookBody only handled JSON and urlencoded, so every delivery would have died as a 400 before reaching a handler. An uploaded part is reduced to its filename so a stray file cannot inflate the execution input
  • Registration is idempotent. Jotform keeps a form's webhooks as a plain list and does not treat the URL as a key, so posting one it already holds would leave the form delivering every submission twice
  • Nothing persists the external webhook id. Jotform identifies webhooks by position and renumbers them on insert (the documented POST sample returns the new entry as "0"), so create and delete both re-resolve the id by matching the callback URL, ignoring a trailing slash

Notes

Outputs are mapped from fields confirmed against Jotform's API reference and a captured delivery: formID, submissionID, formTitle, username, ip, type, pretty, rawRequest.

Answers are exposed as the parsed rawRequest rather than re-keyed by question label. Labels are not unique, and filtering to q{qid}_ keys would silently drop file answers — those land under the bare slugified label as upload URLs.

Jotform sends no signature or shared secret, so there is no verifyAuth; the webhook path is the credential, as with other unsigned providers.

Type of Change

  • New feature (non-breaking change which adds functionality)

Testing

  • 15 provider handler tests plus 3 body-parser tests; each new guard verified by reverting it and confirming the tests go red
  • bun run type-check, bun run lint, bun run check:audits (29/29), and check-block-registry against staging all pass
  • Full lib/webhooks + triggers + blocks + tools/jotform suite: 1622 passing
  • Not exercised against a live Jotform form

Checklist

  • Code follows project style guidelines
  • Self-reviewed my changes
  • Tests added/updated and passing
  • No new warnings introduced
  • I confirm that I have read and agree to the terms outlined in the Contributor License Agreement (CLA)

Jotform's only webhook event is a new submission, so the block gets one
trigger. Deploying it registers the callback on the form through the API
and undeploying removes it again.

Two things about this provider needed handling:

Jotform posts submissions as multipart/form-data, which the shared webhook
body parser did not read — the delivery died as a 400 before any handler
saw it. The parser now flattens a multipart body the same way it already
flattens a urlencoded one, reducing an uploaded part to its filename so a
stray file cannot inflate the execution input.

The form's webhooks are identified by their position in the form's webhook
map, so an id captured at registration goes stale the moment any other
webhook on that form is removed. Nothing persists it; cleanup re-resolves
the id by matching the callback URL. Registration checks the same way,
because Jotform answers a rejected request with the unchanged list rather
than an error.

Answers are exposed as the parsed `rawRequest` rather than re-keyed by
question label — the labels are not unique, and the payload shape is only
documented as the raw q{qid}_{slug} map.

The trigger's region field is named `apiRegion` so it does not collide
with the block's own advanced-mode `region`.
…olerant

Validated the trigger against Jotform's API reference and a captured
delivery (zulip's multipart fixture), which confirmed every mapped field —
formID, submissionID, formTitle, username, ip, type, pretty, rawRequest —
and turned up three things worth correcting.

Jotform keeps a form's webhooks as a plain list and does not treat the URL
as a key, so posting one it already holds leaves the form delivering every
submission twice. Registration now consults the list first and only posts
when the URL is absent. The documented POST sample returns the new entry as
"0", renumbering the rest, which is further reason nothing persists an id.

URL matching no longer lets a trailing slash decide the outcome. Jotform
stores the URL verbatim in every sample seen, but an exact match failing
would hard-fail deploy, and Pipedream's client normalizes the same way.

The rawRequest description claimed the field holds the submitted answers.
A real payload also carries slug, buildDate, submitSource and
jsExecutionTracker, and a file answer appears under the bare slugified
label as upload URLs rather than under a q{qid}_ key — which is also why
filtering to q-prefixed keys would silently drop file answers.
@vercel

vercel Bot commented Aug 18, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
docs Skipped Skipped Aug 18, 2026 12:55am

Request Review

@cursor

cursor Bot commented Aug 18, 2026

Copy link
Copy Markdown

PR Summary

Medium Risk
Changes the shared webhook body parser for all providers and adds subscription lifecycle logic with redeploy edge cases; well covered by tests but affects core webhook infrastructure.

Overview
Adds a Jotform Webhook trigger so workflows start when a watched form gets a new submission. The Jotform block and integration catalog now expose jotform_webhook, with trigger UI fields for form ID, API key, and region.

Shared webhook ingestion now parses multipart/form-data in parseWebhookBody, flattening text fields and reducing file parts to filenames so Jotform deliveries are not rejected as 400s and uploads do not bloat execution input.

A new Jotform webhook provider maps multipart payloads into trigger outputs (including parsed rawRequest), keys idempotency on submissionID, and registers or removes callbacks on the form via the Jotform API on deploy/undeploy. Registration skips duplicate URLs (trailing-slash normalized); teardown skips deletion when another active deployment still shares the same form and callback URL after redeploy.

Reviewed by Cursor Bugbot for commit c50c11e. Configure here.

@greptile-apps

greptile-apps Bot commented Aug 18, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

The PR adds a Jotform submission trigger, including multipart payload parsing and external webhook registration lifecycle management. The latest fix protects the shared callback during redeployment by checking for an active replacement before cleaning up the retired registration.

  • Registers Jotform callbacks idempotently and resolves webhook IDs by callback URL.
  • Parses Jotform multipart submissions and maps them into trigger outputs.
  • Adds trigger, provider, block, integration, documentation, and test registrations.
  • Preserves callbacks still used by an active deployment during retired-generation cleanup.

Confidence Score: 5/5

The PR appears safe to merge because the previously reported callback deletion failure is addressed and no blocking failure remains.

No blocking failure remains; activation commits the replacement deployment version before retired-webhook cleanup, allowing the teardown guard to detect the active replacement and preserve its callback.

Important Files Changed

Filename Overview
apps/sim/lib/webhooks/providers/jotform.ts Implements Jotform payload normalization and external subscription lifecycle management; the redeployment teardown guard now preserves callbacks used by an active replacement.
apps/sim/lib/webhooks/providers/jotform.test.ts Covers payload mapping, idempotent registration, regional endpoints, cleanup behavior, and preservation of callbacks shared with active deployments.
apps/sim/lib/webhooks/processor.ts Extends shared webhook request parsing to flatten multipart form data while reducing uploaded parts to filenames.
apps/sim/triggers/jotform/webhook.ts Defines the Jotform submission trigger configuration, credentials, setup instructions, and output contract.
apps/sim/blocks/blocks/jotform.ts Exposes the new Jotform trigger through the existing integration block.
apps/sim/triggers/registry.ts Registers the new Jotform trigger in the shared trigger registry.

Sequence Diagram

sequenceDiagram
  participant Deploy as Deployment lifecycle
  participant New as Replacement webhook row
  participant Jotform as Jotform API
  participant Old as Retired webhook row
  participant DB as Deployment state

  Deploy->>New: Prepare candidate registration
  New->>Jotform: Reuse existing callback
  Deploy->>DB: Activate replacement generation
  DB-->>Deploy: Commit active deployment version
  Deploy->>Old: Clean up retired generation
  Old->>DB: Check for active row using same form and callback
  DB-->>Old: Replacement still uses callback
  Old-->>Jotform: Skip callback deletion
Loading

Reviews (2): Last reviewed commit: "fix(jotform): keep the callback when an ..." | Re-trigger Greptile

Comment thread apps/sim/lib/webhooks/providers/jotform.ts
Redeploying prepares the replacement webhook row alongside the live one and
a workflow keeps its path across deployments, so both rows resolve to a
single callback on a single form. Registration adopts the callback already
present instead of posting a duplicate, which left the retired row's
cleanup deleting the one the new row had just adopted — the trigger went
silent after a redeploy that changed the trigger config.

Teardown now skips when another webhook row belonging to an active
deployment resolves to the same form and callback URL, matching how the
Telegram handler skips deleteWebhook while an active deployment still uses
the same bot. A genuine undeploy has no such row and still cleans up.
@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@greptile

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@cursor review

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit c50c11e. Configure here.

@waleedlatif1
waleedlatif1 merged commit d17a11f into staging Aug 18, 2026
30 checks passed
@waleedlatif1
waleedlatif1 deleted the feat/jotform-trigger branch August 18, 2026 01:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant