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​