Skip to main content

Forms API

Overview

The Forms API provides comprehensive management of web forms for lead capture, data collection, and customer engagement. Built on the powerful SurveyJS framework, Stack9 Forms enable you to create sophisticated multi-page forms with advanced logic, custom themes, and seamless integration with your marketing automation workflows.

Resource Description

Forms in Stack9 consist of:

  • Form Configuration: Core form settings including name, type, and CORS configuration
  • SurveyJS Schema: Complete form structure with pages, questions, validation rules, and conditional logic
  • Form Themes: Visual styling and branding options for consistent user experience
  • Submission Management: Capture and process form responses with automatic subscriber creation
  • Post-Submit Actions: Configurable actions triggered after form submission
  • Analytics & Tracking: Monitor form performance, conversion rates, and user behavior

Key Features

  • Visual Form Builder: Create forms using SurveyJS's powerful drag-and-drop interface
  • Advanced Question Types: Support for 20+ question types including matrices, ratings, and file uploads
  • Conditional Logic: Show/hide questions based on previous answers
  • Multi-Page Forms: Create wizard-style forms with progress indicators
  • Custom Themes: Apply branded themes with full control over colors, fonts, and layout
  • CORS Configuration: Secure form embedding with domain whitelist controls
  • Real-Time Validation: Client-side and server-side validation rules
  • Submission Tracking: Complete audit trail of all form submissions
  • Lead Capture Integration: Automatic subscriber creation from form submissions
  • Journey Triggers: Initiate marketing automation workflows on form completion

Authentication

All endpoints require API key authentication:

X-API-Key: your-api-key-here

Form Settings

Get Form Settings

Retrieve configuration options and metadata for form management.

GET /api/forms/settings

Example Request

curl -X GET \
https://apis.app.stack9.co/api/forms/settings \
-H 'X-API-Key: your-api-key-here'

Example Response

{
"formTypes": [
{
"key": "embedded_form",
"name": "Embedded Form",
"description": "Form that can be embedded in external websites"
}
],
"postSubmitActionTypes": [
{
"key": "redirect",
"name": "Redirect to URL",
"description": "Redirect user to a specific URL after submission"
},
{
"key": "show_message",
"name": "Show Message",
"description": "Display a custom thank you message"
},
{
"key": "trigger_journey",
"name": "Trigger Journey",
"description": "Start a marketing automation journey"
}
],
"surveyLicenseKey": "xxxxx-xxxxx-xxxxx"
}

Form Management

Create Form

Create a new form with SurveyJS configuration and settings.

POST /api/forms

Parameters

ParameterTypeRequiredDescription
namestringYesDisplay name for the form
allowed_originsarrayYesDomains allowed to embed this form. Use ["*"] for all domains
activebooleanYesWhether form accepts submissions
form_typestringYesType of form (must be "embedded_form")
business_unitstringNoBusiness unit identifier
surveyJsOptionsobjectYesComplete SurveyJS form configuration
surveyJsOptions.titlestringNoForm title displayed to users
surveyJsOptions.descriptionstringNoForm description or instructions
surveyJsOptions.logostringNoLogo URL for form header
surveyJsOptions.pagesarrayYesArray of form pages with questions
surveyJsOptions.completedHtmlstringNoHTML shown after form completion
surveyJsOptions.showProgressBarstringNoProgress bar display ("top", "bottom", "both", "none")

Example Request

curl -X POST \
https://apis.app.stack9.co/api/forms \
-H 'X-API-Key: your-api-key-here' \
-H 'Content-Type: application/json' \
-d '{
"name": "Newsletter Signup",
"allowed_origins": ["https://example.com", "https://www.example.com"],
"active": true,
"form_type": "embedded_form",
"business_unit": "marketing",
"surveyJsOptions": {
"title": "Join Our Newsletter",
"description": "Get weekly updates and exclusive content",
"logo": "https://example.com/logo.png",
"logoWidth": "200px",
"logoHeight": "60px",
"logoPosition": "right",
"showProgressBar": "top",
"completedHtml": "<h3>Thank you!</h3><p>You have been successfully subscribed.</p>",
"pages": [
{
"name": "page1",
"title": "Contact Information",
"elements": [
{
"type": "text",
"name": "email",
"title": "Email Address",
"inputType": "email",
"isRequired": true,
"validators": [
{
"type": "email",
"text": "Please enter a valid email address"
}
]
},
{
"type": "text",
"name": "firstName",
"title": "First Name",
"isRequired": true
},
{
"type": "text",
"name": "lastName",
"title": "Last Name",
"isRequired": false
},
{
"type": "dropdown",
"name": "interests",
"title": "What are you interested in?",
"choices": [
"Product Updates",
"Industry News",
"Tips & Tutorials",
"Case Studies"
],
"isRequired": true
}
]
},
{
"name": "page2",
"title": "Preferences",
"elements": [
{
"type": "radiogroup",
"name": "frequency",
"title": "How often would you like to hear from us?",
"choices": [
"Weekly",
"Bi-weekly",
"Monthly"
],
"defaultValue": "Weekly"
},
{
"type": "checkbox",
"name": "consent",
"title": "I agree to receive marketing communications",
"isRequired": true,
"validators": [
{
"type": "expression",
"text": "You must agree to continue",
"expression": "{consent} = true"
}
]
}
]
}
]
}
}'

Example Response

{
"code": "form_Xk9mNp2Q"
}

List Forms

Retrieve a paginated list of forms with advanced filtering options.

POST /api/forms/list

Parameters

ParameterTypeRequiredDescription
pagenumberYesPage number (1-based)
limitnumberYesItems per page (max: 100)
searchstringNoSearch across form names
filtersobjectYesFilter criteria object
filters.nameobjectNoFilter by form name
filters.activeobjectNoFilter by active status
filters.form_typeobjectNoFilter by form type
filters.created_atobjectNoFilter by creation date

Filter Operations

Each filter field supports these operations:

  • eq: Equals
  • ne: Not equals
  • like: Contains (for strings)
  • gt, gte, lt, lte: Comparison operators
  • in: Value in array
  • between: Between two values

Example Request

curl -X POST \
https://apis.app.stack9.co/api/forms/list \
-H 'X-API-Key: your-api-key-here' \
-H 'Content-Type: application/json' \
-d '{
"page": 1,
"limit": 20,
"search": "newsletter",
"filters": {
"active": {
"operation": "eq",
"value": true
},
"form_type": {
"operation": "eq",
"value": "embedded_form"
},
"created_at": {
"operation": "gte",
"value": "2024-01-01T00:00:00.000Z"
}
}
}'

Example Response

{
"results": [
{
"version": 2,
"created_at": "2024-01-15T10:30:00.123Z",
"updated_at": "2024-03-20T14:45:30.456Z",
"code": "form_Xk9mNp2Q",
"public_code": "pub_form_Abc123",
"name": "Newsletter Signup",
"allowed_origins": ["https://example.com"],
"active": true,
"form_type": "embedded_form",
"business_unit": "marketing",
"surveyJsOptions": {
"title": "Join Our Newsletter",
"pages": [...]
},
"submission_count": 1523,
"conversion_rate": 68.5
}
],
"total": 15,
"totalPages": 1
}

Get Form by Code

Retrieve a specific form by its unique code.

GET /api/forms/{code}

Parameters

ParameterTypeRequiredDescription
codestringYesForm code (path parameter)

Example Request

curl -X GET \
https://apis.app.stack9.co/api/forms/form_Xk9mNp2Q \
-H 'X-API-Key: your-api-key-here'

Example Response

{
"version": 2,
"created_at": "2024-01-15T10:30:00.123Z",
"updated_at": "2024-03-20T14:45:30.456Z",
"code": "form_Xk9mNp2Q",
"public_code": "pub_form_Abc123",
"name": "Newsletter Signup",
"allowed_origins": ["https://example.com", "https://www.example.com"],
"active": true,
"form_type": "embedded_form",
"business_unit": "marketing",
"surveyJsOptions": {
"title": "Join Our Newsletter",
"description": "Get weekly updates and exclusive content",
"logo": "https://example.com/logo.png",
"logoWidth": "200px",
"logoHeight": "60px",
"pages": [
{
"name": "page1",
"title": "Contact Information",
"elements": [
{
"type": "text",
"name": "email",
"title": "Email Address",
"inputType": "email",
"isRequired": true
}
]
}
],
"completedHtml": "<h3>Thank you!</h3>"
}
}

Get Form Schema with Theme

Retrieve form configuration along with its associated theme for rendering.

GET /api/forms/{code}/schema

This endpoint returns the complete form definition including theme configuration, useful for embedding and rendering forms in external applications.

Parameters

ParameterTypeRequiredDescription
codestringYesForm code (path parameter)

Example Request

curl -X GET \
https://apis.app.stack9.co/api/forms/form_Xk9mNp2Q/schema \
-H 'X-API-Key: your-api-key-here'

Example Response

{
"form": {
"code": "form_Xk9mNp2Q",
"public_code": "pub_form_Abc123",
"name": "Newsletter Signup",
"surveyJsOptions": {
"title": "Join Our Newsletter",
"pages": [...]
}
},
"theme": {
"code": "theme_Def456",
"name": "Brand Theme",
"surveyJsThemeOptions": {
"themeName": "modern",
"colorPalette": "light",
"isPanelless": true,
"primaryColor": "#2563eb",
"backgroundImage": "https://example.com/bg.jpg",
"backgroundImageFit": "cover"
}
}
}

Update Form

Update an existing form's configuration.

PUT /api/forms/{code}

Parameters

Same as Create Form. All fields provided will update the existing values.

Example Request

curl -X PUT \
https://apis.app.stack9.co/api/forms/form_Xk9mNp2Q \
-H 'X-API-Key: your-api-key-here' \
-H 'Content-Type: application/json' \
-d '{
"name": "Updated Newsletter Form",
"allowed_origins": ["*"],
"active": true,
"form_type": "embedded_form",
"surveyJsOptions": {
"title": "Subscribe to Our Newsletter",
"description": "Updated description",
"pages": [...]
}
}'

Example Response

{
"success": true,
"code": "form_Xk9mNp2Q"
}

Form Themes

Create Form Theme

Create a custom theme for styling forms.

POST /api/form_themes

Parameters

ParameterTypeRequiredDescription
namestringYesTheme name
surveyJsThemeOptionsobjectYesSurveyJS theme configuration
surveyJsThemeOptions.themeNamestringNoBase theme name
surveyJsThemeOptions.colorPalettestringNoColor palette ("light" or "dark")
surveyJsThemeOptions.isPanellessbooleanNoRemove panel borders
surveyJsThemeOptions.backgroundImagestringNoBackground image URL
surveyJsThemeOptions.backgroundImageFitstringNoImage fit mode ("auto", "contain", "cover")
surveyJsThemeOptions.backgroundOpacitynumberNoBackground opacity (0-1)
surveyJsThemeOptions.primaryColorstringNoPrimary brand color
surveyJsThemeOptions.headerobjectNoHeader configuration

Example Request

curl -X POST \
https://apis.app.stack9.co/api/form_themes \
-H 'X-API-Key: your-api-key-here' \
-H 'Content-Type: application/json' \
-d '{
"name": "Modern Blue Theme",
"surveyJsThemeOptions": {
"themeName": "modern",
"colorPalette": "light",
"isPanelless": true,
"primaryColor": "#2563eb",
"backgroundImage": "https://example.com/gradient-bg.jpg",
"backgroundImageFit": "cover",
"backgroundImageAttachment": "fixed",
"backgroundOpacity": 0.1,
"header": {
"height": 200,
"inheritWidthFrom": "container",
"textAreaWidth": 768,
"logoPositionX": "right",
"logoPositionY": "middle",
"titlePositionX": "left",
"titlePositionY": "middle",
"descriptionPositionX": "left",
"descriptionPositionY": "bottom",
"overlapEnabled": false,
"backgroundImageOpacity": 0.8
},
"cssVariables": {
"--primary-color": "#2563eb",
"--primary-light": "#60a5fa",
"--primary-dark": "#1e40af",
"--background": "#ffffff",
"--background-dim": "#f9fafb",
"--foreground": "#1f2937",
"--border": "#e5e7eb",
"--font-family": "Inter, system-ui, sans-serif",
"--base-unit": "8px",
"--corner-radius": "6px"
}
}
}'

Example Response

{
"code": "theme_Def456"
}

List Form Themes

Retrieve available form themes.

POST /api/form_themes/list

Parameters

ParameterTypeRequiredDescription
pagenumberYesPage number (1-based)
limitnumberYesItems per page (max: 100)
filtersobjectNoFilter criteria

Example Request

curl -X POST \
https://apis.app.stack9.co/api/form_themes/list \
-H 'X-API-Key: your-api-key-here' \
-H 'Content-Type: application/json' \
-d '{
"page": 1,
"limit": 20,
"filters": {}
}'

Example Response

{
"results": [
{
"version": 1,
"created_at": "2024-01-15T10:30:00.123Z",
"updated_at": "2024-01-15T10:30:00.123Z",
"code": "theme_Def456",
"name": "Modern Blue Theme",
"surveyJsThemeOptions": {
"themeName": "modern",
"colorPalette": "light",
"primaryColor": "#2563eb"
}
},
{
"code": "theme_Default",
"name": "Default Theme",
"surveyJsThemeOptions": {
"themeName": "default"
}
}
],
"total": 5,
"totalPages": 1
}

Get Form Theme by Code

Retrieve a specific theme configuration.

GET /api/form_themes/{code}

Parameters

ParameterTypeRequiredDescription
codestringYesTheme code (path parameter)

Example Request

curl -X GET \
https://apis.app.stack9.co/api/form_themes/theme_Def456 \
-H 'X-API-Key: your-api-key-here'

Example Response

{
"version": 1,
"created_at": "2024-01-15T10:30:00.123Z",
"updated_at": "2024-01-15T10:30:00.123Z",
"code": "theme_Def456",
"name": "Modern Blue Theme",
"surveyJsThemeOptions": {
"themeName": "modern",
"colorPalette": "light",
"isPanelless": true,
"primaryColor": "#2563eb",
"backgroundImage": "https://example.com/gradient-bg.jpg",
"backgroundImageFit": "cover",
"header": {
"height": 200,
"logoPositionX": "right",
"titlePositionX": "left"
}
}
}

Update Form Theme

Update an existing theme configuration.

PUT /api/form_themes/{code}

Parameters

Same as Create Form Theme.

Example Request

curl -X PUT \
https://apis.app.stack9.co/api/form_themes/theme_Def456 \
-H 'X-API-Key: your-api-key-here' \
-H 'Content-Type: application/json' \
-d '{
"name": "Updated Blue Theme",
"surveyJsThemeOptions": {
"themeName": "modern",
"colorPalette": "dark",
"primaryColor": "#3b82f6"
}
}'

Form Submissions

Create Form Submission

Submit data to a form. This endpoint is typically called from embedded forms.

POST /api/form_submissions

Parameters

ParameterTypeRequiredDescription
form_codestringYesThe form code this submission is for
email_addressstringYesResponder's email address
form_dataobjectYesForm response data as key-value pairs

Example Request

curl -X POST \
https://apis.app.stack9.co/api/form_submissions \
-H 'X-API-Key: your-api-key-here' \
-H 'Content-Type: application/json' \
-d '{
"form_code": "form_Xk9mNp2Q",
"email_address": "john.doe@example.com",
"form_data": {
"email": "john.doe@example.com",
"firstName": "John",
"lastName": "Doe",
"interests": "Product Updates",
"frequency": "Weekly",
"consent": true,
"company": "Acme Corp",
"phone": "+1-555-0123"
}
}'

Example Response

{
"submission_id": "sub_9kL3mP5n"
}

Error Responses

400 Bad Request
{
"message": "Invalid submission data",
"code": "INVALID_SUBMISSION",
"issues": [
{
"field": "email_address",
"message": "Invalid email format"
}
]
}
404 Not Found
{
"message": "Form not found or inactive",
"code": "FORM_NOT_FOUND"
}

List Form Submissions

Retrieve form submissions with filtering options.

POST /api/form_submissions/list

Parameters

ParameterTypeRequiredDescription
pagenumberYesPage number (1-based)
limitnumberYesItems per page (max: 100)
filtersobjectYesFilter criteria
filters.form_codeobjectNoFilter by form
filters.email_addressobjectNoFilter by email
filters.created_atobjectNoFilter by submission date

Example Request

curl -X POST \
https://apis.app.stack9.co/api/form_submissions/list \
-H 'X-API-Key: your-api-key-here' \
-H 'Content-Type: application/json' \
-d '{
"page": 1,
"limit": 50,
"filters": {
"form_code": {
"operation": "eq",
"value": "form_Xk9mNp2Q"
},
"created_at": {
"operation": "between",
"value": ["2024-01-01T00:00:00.000Z", "2024-12-31T23:59:59.999Z"]
}
}
}'

Example Response

{
"results": [
{
"id": "sub_9kL3mP5n",
"created_at": "2024-03-20T14:30:15.234Z",
"form_code": "form_Xk9mNp2Q",
"form_name": "Newsletter Signup",
"email_address": "john.doe@example.com",
"form_data": {
"firstName": "John",
"lastName": "Doe",
"interests": "Product Updates",
"frequency": "Weekly"
},
"subscriber_created": true,
"journey_triggered": false,
"ip_address": "192.168.1.1",
"user_agent": "Mozilla/5.0..."
}
],
"total": 1523,
"totalPages": 31
}

Form Embedding

Embedding Forms in Websites

Forms can be embedded in external websites using the following methods:

Method 1: iFrame Embedding

<iframe
src="https://forms.stack9.io/embed/pub_form_Abc123"
width="100%"
height="600"
frameborder="0"
style="border: 0; max-width: 100%;">
</iframe>

Method 2: JavaScript SDK

<!-- Stack9 Forms SDK -->
<script src="https://cdn.stack9.io/forms/v1/sdk.js"></script>

<div id="stack9-form"></div>

<script>
Stack9Forms.render({
container: 'stack9-form',
formCode: 'pub_form_Abc123',
theme: 'theme_Def456',
onComplete: function(submission) {
console.log('Form submitted:', submission.id);
// Custom completion logic
},
onError: function(error) {
console.error('Form error:', error);
}
});
</script>

Method 3: React Component

import { Stack9Form } from '@stack9/forms-react';

function NewsletterSignup() {
const handleComplete = (submission) => {
console.log('Form submitted:', submission.id);
};

return (
<Stack9Form
formCode="pub_form_Abc123"
theme="theme_Def456"
onComplete={handleComplete}
customData={{
source: 'website',
campaign: 'spring-2024'
}}
/>
);
}

CORS Configuration

To embed forms on external domains, configure the allowed_origins field:

{
"allowed_origins": [
"https://example.com",
"https://www.example.com",
"https://blog.example.com"
]
}

Use ["*"] to allow embedding on any domain (not recommended for production).


Advanced Features

Conditional Logic

Implement dynamic form behavior based on user responses:

{
"pages": [
{
"elements": [
{
"type": "radiogroup",
"name": "customerType",
"title": "Are you a new or existing customer?",
"choices": ["New Customer", "Existing Customer"]
},
{
"type": "text",
"name": "accountNumber",
"title": "Account Number",
"visibleIf": "{customerType} = 'Existing Customer'",
"isRequired": true
},
{
"type": "dropdown",
"name": "howHeard",
"title": "How did you hear about us?",
"visibleIf": "{customerType} = 'New Customer'",
"choices": ["Google", "Social Media", "Friend", "Other"]
}
]
}
]
}

Custom Validation

Add custom validation rules to form fields:

{
"elements": [
{
"type": "text",
"name": "age",
"title": "Age",
"inputType": "number",
"validators": [
{
"type": "numeric",
"minValue": 18,
"maxValue": 120,
"text": "Age must be between 18 and 120"
}
]
},
{
"type": "text",
"name": "couponCode",
"title": "Coupon Code",
"validators": [
{
"type": "regex",
"regex": "^[A-Z]{3}-[0-9]{4}$",
"text": "Invalid coupon format (e.g., ABC-1234)"
}
]
}
]
}

Multi-Language Support

Configure forms for multiple languages:

{
"locale": "es",
"title": {
"default": "Newsletter Signup",
"es": "Suscripción al Boletín",
"fr": "Inscription à la Newsletter"
},
"pages": [
{
"elements": [
{
"type": "text",
"name": "email",
"title": {
"default": "Email Address",
"es": "Dirección de Correo",
"fr": "Adresse E-mail"
}
}
]
}
]
}

File Upload Support

Enable file uploads in forms:

{
"elements": [
{
"type": "file",
"name": "resume",
"title": "Upload Resume",
"acceptedTypes": ".pdf,.doc,.docx",
"maxSize": 5242880,
"storeDataAsText": false,
"waitForUpload": true
}
]
}

Integration with Marketing Automation

Automatic Subscriber Creation

Form submissions automatically create or update subscriber profiles:

  1. New Subscribers: Created with form data mapped to profile fields
  2. Existing Subscribers: Profile updated with latest form data
  3. Custom Field Mapping: Map form fields to subscriber custom fields
  4. Audience Assignment: Auto-assign to specified audiences
  5. Subscription Preferences: Set initial subscription preferences

Journey Triggers

Configure forms to trigger marketing journeys on submission:

{
"post_submit_actions": [
{
"type": "trigger_journey",
"journey_id": "journey_Welcome123",
"data_mapping": {
"firstName": "form.firstName",
"product_interest": "form.interests"
}
}
]
}

Lead Scoring

Automatically score leads based on form responses:

{
"scoring_rules": [
{
"field": "company_size",
"value": "Enterprise",
"score": 50
},
{
"field": "budget",
"value": "> $100,000",
"score": 30
},
{
"field": "timeline",
"value": "This Quarter",
"score": 20
}
]
}

Analytics and Reporting

Form Performance Metrics

Track key performance indicators:

  • Views: Number of times form was loaded
  • Starts: Users who began filling the form
  • Completions: Successful submissions
  • Conversion Rate: Completions / Views
  • Abandonment Rate: (Starts - Completions) / Starts
  • Average Time: Mean time to complete
  • Drop-off Points: Questions where users abandon

Submission Analytics

Analyze submission patterns:

GET /api/forms/{code}/analytics?period=30d
{
"summary": {
"total_views": 5234,
"total_starts": 2156,
"total_completions": 1523,
"conversion_rate": 29.1,
"abandonment_rate": 29.4
},
"daily_metrics": [
{
"date": "2024-03-20",
"views": 187,
"starts": 76,
"completions": 52,
"conversion_rate": 27.8
}
],
"field_completion": {
"email": 100,
"firstName": 98.5,
"lastName": 76.3,
"phone": 45.2
}
}

Best Practices

Form Design

  1. Keep Forms Short: Limit to essential fields only
  2. Progressive Disclosure: Use multi-page forms for complex data collection
  3. Clear Labels: Use descriptive field labels and help text
  4. Mobile Optimization: Test forms on mobile devices
  5. Smart Defaults: Pre-fill known information when possible

Conversion Optimization

  1. Reduce Friction: Minimize required fields
  2. Social Proof: Add testimonials or trust badges
  3. Progress Indicators: Show completion progress on multi-page forms
  4. Inline Validation: Provide immediate feedback on errors
  5. Clear CTAs: Use action-oriented submit button text

Security Considerations

  1. CORS Configuration: Restrict to known domains
  2. Rate Limiting: Implement submission rate limits
  3. CAPTCHA: Add CAPTCHA for public forms
  4. Data Validation: Validate all inputs server-side
  5. SSL/TLS: Always use HTTPS for form submission

GDPR Compliance

  1. Consent Checkboxes: Include explicit consent fields
  2. Privacy Policy: Link to privacy policy
  3. Data Minimization: Collect only necessary data
  4. Right to Deletion: Provide mechanism to delete submissions
  5. Audit Trail: Maintain logs of consent and data processing

Error Handling

Common Error Codes

CodeDescriptionResolution
FORM_NOT_FOUNDForm code doesn't existVerify form code
FORM_INACTIVEForm is not accepting submissionsActivate form in settings
CORS_ERRORDomain not in allowed originsAdd domain to allowed_origins
VALIDATION_ERRORForm data validation failedCheck field requirements
RATE_LIMITToo many submissionsImplement client-side throttling
DUPLICATE_SUBMISSIONDuplicate submission detectedPrevent double-submits

Retry Strategy

Implement exponential backoff for transient errors:

async function submitFormWithRetry(data, maxRetries = 3) {
let lastError;

for (let i = 0; i < maxRetries; i++) {
try {
return await submitForm(data);
} catch (error) {
lastError = error;

if (error.code === 'RATE_LIMIT' || error.code === 'SERVER_ERROR') {
const delay = Math.pow(2, i) * 1000; // Exponential backoff
await new Promise(resolve => setTimeout(resolve, delay));
} else {
throw error; // Non-retryable error
}
}
}

throw lastError;
}

Code Examples

Creating a Multi-Step Lead Generation Form

const leadGenForm = {
name: "Enterprise Lead Generation",
active: true,
form_type: "embedded_form",
allowed_origins: ["https://enterprise.example.com"],
surveyJsOptions: {
title: "Get a Custom Quote",
showProgressBar: "top",
pages: [
{
name: "contact",
title: "Contact Information",
elements: [
{
type: "text",
name: "firstName",
title: "First Name",
isRequired: true
},
{
type: "text",
name: "lastName",
title: "Last Name",
isRequired: true
},
{
type: "text",
name: "email",
title: "Business Email",
inputType: "email",
isRequired: true,
validators: [{
type: "email",
text: "Please enter a valid business email"
}]
},
{
type: "text",
name: "phone",
title: "Phone Number",
inputType: "tel",
isRequired: true
}
]
},
{
name: "company",
title: "Company Information",
elements: [
{
type: "text",
name: "company",
title: "Company Name",
isRequired: true
},
{
type: "dropdown",
name: "industry",
title: "Industry",
isRequired: true,
choices: [
"Technology",
"Healthcare",
"Finance",
"Retail",
"Manufacturing",
"Other"
]
},
{
type: "radiogroup",
name: "companySize",
title: "Company Size",
isRequired: true,
choices: [
"1-10 employees",
"11-50 employees",
"51-200 employees",
"201-1000 employees",
"1000+ employees"
]
}
]
},
{
name: "requirements",
title: "Your Requirements",
elements: [
{
type: "checkbox",
name: "products",
title: "Which products are you interested in?",
isRequired: true,
choices: [
"Email Marketing",
"SMS Marketing",
"Marketing Automation",
"Customer Data Platform",
"Analytics & Reporting"
],
minSelectedChoices: 1
},
{
type: "radiogroup",
name: "budget",
title: "Estimated Annual Budget",
isRequired: true,
choices: [
"< $10,000",
"$10,000 - $50,000",
"$50,000 - $100,000",
"$100,000 - $500,000",
"> $500,000"
]
},
{
type: "comment",
name: "message",
title: "Additional Requirements",
rows: 4
}
]
}
],
completedHtml: "<h3>Thank you for your interest!</h3><p>Our team will contact you within 24 hours.</p>"
}
};

// Create the form
const response = await fetch('https://apis.app.stack9.co/api/forms', {
method: 'POST',
headers: {
'X-API-Key': 'your-api-key',
'Content-Type': 'application/json'
},
body: JSON.stringify(leadGenForm)
});

const { code } = await response.json();
console.log(`Form created: ${code}`);

Handling Form Submissions with Webhooks

// Express.js webhook handler
app.post('/webhooks/form-submission', async (req, res) => {
const { form_code, email_address, form_data } = req.body;

try {
// Score the lead
const leadScore = calculateLeadScore(form_data);

// Create or update subscriber
const subscriber = await createOrUpdateSubscriber({
email: email_address,
firstName: form_data.firstName,
lastName: form_data.lastName,
customFields: {
company: form_data.company,
industry: form_data.industry,
leadScore: leadScore
},
audiences: ['leads', form_data.industry.toLowerCase()]
});

// Trigger appropriate journey based on score
if (leadScore >= 80) {
await triggerJourney('hot-lead-nurture', subscriber.id);
await notifySalesTeam(subscriber, form_data);
} else if (leadScore >= 50) {
await triggerJourney('warm-lead-nurture', subscriber.id);
} else {
await triggerJourney('cold-lead-nurture', subscriber.id);
}

// Send to CRM
await syncToCRM({
email: email_address,
data: form_data,
score: leadScore
});

res.json({ success: true });
} catch (error) {
console.error('Submission processing failed:', error);
res.status(500).json({ error: 'Processing failed' });
}
});

function calculateLeadScore(data) {
let score = 0;

// Company size scoring
if (data.companySize === '1000+ employees') score += 30;
else if (data.companySize === '201-1000 employees') score += 20;
else if (data.companySize === '51-200 employees') score += 10;

// Budget scoring
if (data.budget === '> $500,000') score += 40;
else if (data.budget === '$100,000 - $500,000') score += 30;
else if (data.budget === '$50,000 - $100,000') score += 20;

// Product interest scoring
const productCount = data.products?.length || 0;
score += productCount * 5;

// Industry scoring
if (['Technology', 'Finance'].includes(data.industry)) score += 10;

return Math.min(score, 100);
}

Troubleshooting

Form Not Loading

Issue: Form doesn't appear when embedded

Solutions:

  1. Check CORS configuration in allowed_origins
  2. Verify form is active
  3. Check browser console for JavaScript errors
  4. Ensure form code is correct
  5. Test with allowed_origins: ["*"] temporarily

Submissions Not Recording

Issue: Form submits but no data saved

Solutions:

  1. Verify API key has write permissions
  2. Check form_code matches active form
  3. Validate email_address format
  4. Check rate limits
  5. Review server logs for errors

Styling Issues

Issue: Form doesn't match website design

Solutions:

  1. Create custom theme with matching colors
  2. Use CSS overrides in embedding page
  3. Set isPanelless: true for minimal styling
  4. Adjust container width and responsive settings
  5. Test across different browsers

Performance Optimization

Issue: Form loads slowly

Solutions:

  1. Minimize number of form fields
  2. Lazy load form on user interaction
  3. Use CDN for form assets
  4. Enable browser caching
  5. Optimize image sizes in themes

Additional Resources