Integrations
Forms is designed to connect with the rest of Votel — CRM, Workflows, Click Tracking, Payments — and expose its submission data to external systems via API. This page covers each integration surface.
CRM (Contacts)
Every form submission becomes a CRM lead by default. The integration is automatic — there's no setup beyond mapping individual fields to contact properties.
Field-to-Contact Mapping
In each field's Properties tab, the Save to Contact Field dropdown maps the field's value to a property on the contact created from each submission. Fields from the Contact & Personal palette category come pre-mapped (First Name → first_name, Email → email, etc.).
Fields with no mapping live only on the submission row and don't propagate to the contact record. Use this to keep arbitrary form data in submissions without polluting the contact schema.
See Field Properties → Save to Contact Field for the full list of contact properties you can map to.
Lead De-Duplication
The lead matcher attempts to find an existing contact before creating a new one. Match priority is localStorage.votel_lead_id → email → phone → name. See Submissions → Lead Matching for the algorithm.
Updating Existing Contacts
When a submission matches an existing lead, the contact is updated with any new mapped values. Existing properties are not overwritten with empty strings — only non-empty new values replace old ones.
This means a returning visitor filling out a different form can enrich their existing record without losing prior data.
Workflows
Every form can trigger workflows. Workflows are the way to take action on each submission — send emails, notify your team, enroll in campaigns, route leads, score, tag.
The "Form Submitted" Trigger
In the Workflows builder, add a trigger of type Form Submitted and pick a specific form. The workflow runs once per submission to that form.
Available variables in the workflow:
| Variable | Contents |
|---|---|
submission.id | Submission UUID |
submission.form_id | Form UUID |
submission.form_name | Form name at time of submit |
submission.lead_id | Lead UUID |
submission.responses | Object — field UUID → value |
submission.responses.<field-slug> | Direct access to a field's value by its (immutable) slug |
submission.metadata | Stripe / payment metadata, if any |
lead.first_name / lead.email / etc. | Standard lead variables |
Common Workflow Patterns
| Pattern | Setup |
|---|---|
| Confirmation email | Form Submitted → Email node sending to {{lead.email}} |
| Slack notification | Form Submitted → Slack node posting {{lead.first_name}} just signed up for {{submission.form_name}} |
| Tag the lead | Form Submitted → Tag Lead node with a fixed tag like Form Lead — Newsletter |
| Lead scoring | Form Submitted → Update Contact node bumping lead_score by N |
| Pipeline stage update | Form Submitted → Set Pipeline node moving the lead to "New Inquiry" |
| Outbound campaign enrollment | Form Submitted → Add to Campaign node |
| Conditional routing | Form Submitted → Decision node branching on submission.responses.<field> value |
Multiple Workflows Per Form
You can have multiple workflows triggered by the same form. They all run in parallel on each submission. Useful for separating concerns (one workflow for email confirmations, another for CRM tagging, another for Slack notifications).
Click Tracking Attribution
If your form is reached via a Click Tracking link, attribution is automatic.
When a visitor clicks a tracked link and lands on your form (or arrives with a click_id URL parameter), the form's submission row carries the visitor's lead_visitor_id, which the click engine uses to attribute conversions back to the originating click.
Set up:
- Add a Conversion Pixel on your form's success page (the redirect target after submit).
- The pixel reads the
click_idfrom the URL or local storage and attributes the conversion.
Now your reports show clicks → form submissions → revenue end-to-end.
Stripe Payments
When a form has a Payment field, Stripe handles the actual money movement. The form-builder knows about your connected Stripe account through Settings → Integrations → Stripe.
Connecting Stripe
- Go to Settings → Integrations.
- Click Connect Stripe and complete the OAuth flow.
- Your account's products show up in the Payment field's product dropdown.
Once connected, Payment fields can take charges — see Payment Fields for modes.
Recurring Subscriptions
When a Payment field's mode is Sell Products and a product is configured for MONTHLY / YEARLY / QUARTERLY billing, submitting the form creates a Stripe customer + subscription. The lead is then linked to the Stripe customer, and you can manage subscriptions from Payment & Billing → Subscriptions.
Webhooks
Stripe events (subscription created, charge succeeded, charge failed, subscription updated) flow back through your account's Stripe webhook into the CRM, updating the lead's billing status and triggering any subscription-aware workflows.
Public Submission API
You can submit to a form programmatically without going through the hosted UI. POST to:
POST /api/forms/public/{slug}/submit
Body:
{
"responses": {
"<field-uuid>": "<value>",
"...": "..."
},
"is_final": true,
"submission_id": null,
"submitted_from_page": "https://your-app.com/...",
"referrer_url": "https://google.com/...",
"is_embedded": false
}
Response:
{
"submission_id": "...",
"lead_id": "..."
}
Use this when you want to write submissions from your own backend (e.g. importing form responses from another system, or adding submissions during a programmatic flow).
File Upload API
For File Upload fields, the upload endpoint:
POST /api/forms/public/{slug}/upload
Multipart body with a single file field. Returns:
{
"url": "/api/upload/<tenant>/attachment/<uuid>.<ext>",
"filename": "<uuid>.<ext>",
"original_filename": "<original>",
"size": 12345,
"content_type": "application/pdf"
}
The returned url is what you put into the form's responses payload for that field's UUID.
Reporting API
For querying submissions:
POST /api/form-submission-reporting/query
Body lets you specify form, columns, filters, sort, limit/offset for paginated reports. See Submissions → Dynamic Query API.
Workflows Variables Inside Forms
Inside the form builder itself, you can reference workflow-set variables on the lead via templating in places that support it (label text, statement bodies, ending screen titles). Use:
{{lead.first_name}}
{{lead.company}}
These render server-side when the form is fetched, so the visitor sees their personalized data on form load (only works for returning visitors with cached lead context).
Next Steps
- Workflows Overview — Build workflows triggered by submissions
- Click Tracking — Attribution and conversion tracking
- Payment Fields — Selling products on a form
- Submissions — Where the data lands and how to read it