Skip to main content
Arcanflows

Forms API

Complete API reference for creating forms, handling submissions, public endpoints, and conversational form chat.

Overview

The Forms API allows you to create, manage, and collect data through forms. Forms support 20 field types, public submission endpoints, file uploads, data table integration, embed codes, analytics, and an AI-powered conversational chat mode.


Endpoint Summary

Form CRUD

MethodEndpointDescription
GET/api/v1/formsList all forms
POST/api/v1/formsCreate a form
GET/api/v1/forms/:idGet a form
GET/api/v1/forms/slug/:slugGet form by slug
PUT/api/v1/forms/:idUpdate a form
DELETE/api/v1/forms/:idDelete a form
POST/api/v1/forms/:id/publishPublish form
POST/api/v1/forms/:id/unpublishUnpublish form
POST/api/v1/forms/:id/archiveArchive form
POST/api/v1/forms/:id/duplicateDuplicate form

Submissions

MethodEndpointDescription
POST/api/v1/forms/:id/submitSubmit form data
GET/api/v1/forms/:id/submissionsList submissions
GET/api/v1/forms/:id/submissions/:submissionIdGet submission
DELETE/api/v1/forms/:id/submissions/:submissionIdDelete submission
GET/api/v1/forms/:id/analyticsForm analytics

Dynamic Fields & Files

MethodEndpointDescription
GET/api/v1/forms/:id/fields/:fieldId/optionsGet field options from data source
GET/api/v1/forms/:id/files/:fileIdDownload uploaded file

Public Endpoints (No Auth Required)

MethodEndpointDescription
GET/api/v1/public/forms/:slugGet public form by slug
POST/api/v1/public/forms/:slug/submitPublic form submission
POST/api/v1/public/forms/:slug/uploadPublic file upload
GET/api/v1/public/forms/:slug/embedGet embed code
GET/api/v1/public/forms/:slug/fields/:fieldId/optionsPublic field options

Form Chat (Conversational Forms)

MethodEndpointDescription
GET/api/v1/public/forms/:slug/conversations/:conversationIdGet conversation
GET/api/v1/public/forms/:slug/conversations/:conversationId/messagesGet messages
POST/api/v1/public/forms/:slug/conversations/:conversationId/messagesSend message
POST/api/v1/public/forms/:slug/conversations/:conversationId/messages/streamStream message

List Forms

GET /api/v1/forms

Query Parameters

ParameterTypeDefaultDescription
pageinteger1Page number
per_pageinteger20Items per page (max 100)
statusstring-Filter: draft, published, archived
searchstring-Search by name
sortstring-created_atSort field (- prefix for descending)

Response

json
{
  "data": [
    {
      "id": "form_abc123",
      "name": "Contact Form",
      "slug": "contact-form",
      "description": "General inquiries form",
      "status": "published",
      "field_count": 5,
      "submission_count": 342,
      "created_at": "2025-11-01T10:00:00Z",
      "updated_at": "2025-12-07T15:30:00Z"
    }
  ],
  "pagination": {
    "page": 1,
    "per_page": 20,
    "total": 8,
    "total_pages": 1
  }
}

Example

bash
curl "/api/v1/forms?status=published" \
  -H "Authorization: Bearer your_api_key"

Create Form

POST /api/v1/forms

Request Body

json
{
  "name": "Contact Form",
  "description": "General inquiries and feedback",
  "fields": [
    {
      "id": "name",
      "type": "text",
      "label": "Full Name",
      "placeholder": "Enter your name",
      "required": true,
      "validation": { "min_length": 2, "max_length": 100 }
    },
    {
      "id": "email",
      "type": "email",
      "label": "Email Address",
      "placeholder": "[email protected]",
      "required": true
    },
    {
      "id": "subject",
      "type": "select",
      "label": "Subject",
      "required": true,
      "options": [
        { "value": "general", "label": "General Inquiry" },
        { "value": "support", "label": "Technical Support" },
        { "value": "sales", "label": "Sales Question" }
      ]
    },
    {
      "id": "rating",
      "type": "rating",
      "label": "How would you rate our service?",
      "required": false,
      "validation": { "max": 5 }
    },
    {
      "id": "message",
      "type": "textarea",
      "label": "Message",
      "placeholder": "How can we help?",
      "required": true,
      "validation": { "min_length": 10, "max_length": 2000 }
    },
    {
      "id": "signature",
      "type": "signature",
      "label": "Your Signature",
      "required": false
    }
  ],
  "settings": {
    "submit_button_text": "Send Message",
    "success_message": "Thank you! We'll get back to you soon.",
    "redirect_url": null,
    "notifications": {
      "email": "[email protected]"
    }
  },
  "data_table_config": {
    "table_id": "dt_contacts",
    "auto_save": true,
    "field_mapping": {
      "name": "full_name",
      "email": "email_address",
      "subject": "inquiry_type",
      "message": "body"
    }
  },
  "workflow_id": "wf_xyz789",
  "branding": {
    "logo_url": "https://company.com/logo.png",
    "primary_color": "#4F46E5",
    "background_color": "#F9FAFB"
  }
}

Form Fields

FieldTypeRequiredDescription
namestringYesForm name (max 100 chars)
descriptionstringNoForm description
fieldsarrayYesForm field definitions
settingsobjectNoForm settings
workflow_idstringNoWorkflow to trigger on submission
data_table_configobjectNoAuto-save submissions to a data table
brandingobjectNoCustom branding

Field Types

TypeDescriptionValidation Options
textSingle-line textmin_length, max_length, pattern
textareaMulti-line textmin_length, max_length
emailEmail addressAuto-validated
phonePhone numberpattern
numberNumeric inputmin, max, step
selectDropdown selectoptions
multi_selectMultiple selectoptions, min_selections, max_selections
checkboxSingle checkbox-
checkbox_groupMultiple checkboxesoptions
radioRadio buttonsoptions
dateDate pickermin_date, max_date
datetimeDate and timemin_date, max_date
fileFile uploadallowed_types, max_size_mb
urlURL inputAuto-validated
hiddenHidden field-
sectionSection divider-
paragraphStatic text block-
signatureSignature pad-
ratingStar/numeric ratingmax
sliderRange slidermin, max, step

Response

json
{
  "data": {
    "id": "form_abc123",
    "name": "Contact Form",
    "slug": "contact-form",
    "description": "General inquiries and feedback",
    "status": "draft",
    "fields": [...],
    "settings": {...},
    "created_at": "2025-12-07T10:00:00Z",
    "updated_at": "2025-12-07T10:00:00Z"
  }
}

Get Form

GET /api/v1/forms/:id

Response

json
{
  "data": {
    "id": "form_abc123",
    "name": "Contact Form",
    "slug": "contact-form",
    "description": "General inquiries and feedback",
    "status": "published",
    "fields": [
      {
        "id": "name",
        "type": "text",
        "label": "Full Name",
        "required": true
      }
    ],
    "settings": {
      "submit_button_text": "Send Message",
      "success_message": "Thank you!"
    },
    "workflow_id": "wf_xyz789",
    "data_table_config": {
      "table_id": "dt_contacts",
      "auto_save": true,
      "field_mapping": { "name": "full_name", "email": "email_address" }
    },
    "branding": {...},
    "stats": {
      "submissions": 342,
      "views": 1520,
      "conversion_rate": 22.5
    },
    "created_at": "2025-11-01T10:00:00Z",
    "updated_at": "2025-12-07T15:30:00Z",
    "published_at": "2025-11-02T09:00:00Z"
  }
}

Get Form by Slug

GET /api/v1/forms/slug/:slug

Same response format as Get Form. Useful when you have the human-readable slug instead of the UUID.


Update Form

PUT /api/v1/forms/:id

Only include fields you want to update. Returns the updated form object.

json
{
  "name": "Updated Contact Form",
  "fields": [...],
  "settings": {
    "success_message": "Thanks for reaching out!"
  }
}

Note: Updating fields on a published form creates a new version. Existing submissions retain their original field structure.


Delete Form

DELETE /api/v1/forms/:id

Returns 204 No Content. This also deletes all submissions. Use archive instead for data retention.


Lifecycle Endpoints

Publish

POST /api/v1/forms/:id/publish

Changes status from draft to published, enabling submissions via public and authenticated endpoints.

json
{
  "data": {
    "id": "form_abc123",
    "status": "published",
    "slug": "contact-form",
    "published_at": "2025-12-07T10:00:00Z"
  }
}

Unpublish

POST /api/v1/forms/:id/unpublish

Returns the form to draft status, disabling public submissions.

Archive

POST /api/v1/forms/:id/archive

Archives the form, preventing new submissions while retaining all existing data and submission history.

Duplicate

POST /api/v1/forms/:id/duplicate

Creates a copy of the form with all fields and settings. The duplicate is created in draft status with a new ID and slug.

json
{
  "data": {
    "id": "form_def456",
    "name": "Contact Form (Copy)",
    "slug": "contact-form-copy",
    "status": "draft",
    "field_count": 5,
    "created_at": "2025-12-07T11:00:00Z"
  }
}

Submit Form

POST /api/v1/forms/:id/submit

Submit data to a form via the authenticated API.

Request Body

json
{
  "data": {
    "name": "John Doe",
    "email": "[email protected]",
    "subject": "general",
    "message": "I have a question about your services.",
    "rating": 4
  },
  "metadata": {
    "source": "api",
    "utm_source": "google"
  }
}

Parameters

FieldTypeRequiredDescription
dataobjectYesForm field values (keys match field IDs)
metadataobjectNoAdditional context metadata

Response

json
{
  "data": {
    "submission_id": "sub_xyz789",
    "form_id": "form_abc123",
    "status": "received",
    "workflow_execution_id": "exec_abc123",
    "created_at": "2025-12-07T10:30:00Z"
  },
  "message": "Thank you! We'll get back to you soon."
}

Validation Errors

json
{
  "error": {
    "code": "validation_error",
    "message": "Form validation failed",
    "details": {
      "errors": [
        { "field": "email", "message": "Invalid email address" },
        { "field": "message", "message": "Must be at least 10 characters" }
      ]
    }
  }
}

List Submissions

GET /api/v1/forms/:id/submissions

Query Parameters

ParameterTypeDefaultDescription
pageinteger1Page number
per_pageinteger20Items per page
statusstring-Filter: received, processed, archived
afterstring-Submissions after ISO date
beforestring-Submissions before ISO date
searchstring-Search in field values

Response

json
{
  "data": [
    {
      "id": "sub_xyz789",
      "form_id": "form_abc123",
      "status": "processed",
      "data": {
        "name": "John Doe",
        "email": "[email protected]",
        "subject": "general",
        "message": "I have a question..."
      },
      "metadata": {
        "ip_address": "192.168.1.1",
        "user_agent": "Mozilla/5.0...",
        "source": "website"
      },
      "workflow_execution_id": "exec_abc123",
      "created_at": "2025-12-07T10:30:00Z"
    }
  ],
  "pagination": { "page": 1, "per_page": 20, "total": 342, "total_pages": 18 }
}

Get Submission

GET /api/v1/forms/:id/submissions/:submissionId

Response

json
{
  "data": {
    "id": "sub_xyz789",
    "form_id": "form_abc123",
    "form_name": "Contact Form",
    "status": "processed",
    "data": {
      "name": "John Doe",
      "email": "[email protected]",
      "subject": "general",
      "message": "I have a question about your services.",
      "rating": 4
    },
    "metadata": {
      "ip_address": "192.168.1.1",
      "user_agent": "Mozilla/5.0...",
      "source": "website",
      "page_url": "https://company.com/contact",
      "referrer": "https://google.com"
    },
    "files": [
      {
        "field_id": "attachment",
        "file_id": "file_001",
        "filename": "document.pdf",
        "size_bytes": 245000,
        "mime_type": "application/pdf"
      }
    ],
    "workflow_execution": {
      "id": "exec_abc123",
      "status": "completed",
      "output": { "ticket_id": "TKT-12345" }
    },
    "created_at": "2025-12-07T10:30:00Z",
    "processed_at": "2025-12-07T10:30:05Z"
  }
}

Delete Submission

DELETE /api/v1/forms/:id/submissions/:submissionId

Returns 204 No Content.


Form Analytics

GET /api/v1/forms/:id/analytics

Returns aggregated analytics for the form.

json
{
  "data": {
    "total_submissions": 342,
    "total_views": 1520,
    "conversion_rate": 22.5,
    "avg_completion_time_seconds": 45,
    "submissions_by_day": [
      { "date": "2025-12-01", "count": 18 },
      { "date": "2025-12-02", "count": 24 }
    ],
    "top_sources": [
      { "source": "website", "count": 210 },
      { "source": "email", "count": 85 },
      { "source": "api", "count": 47 }
    ],
    "field_completion_rates": {
      "name": 100,
      "email": 100,
      "phone": 68.4,
      "message": 95.2
    },
    "drop_off_fields": [
      { "field_id": "phone", "drop_off_rate": 12.3 }
    ]
  }
}

Dynamic Field Options

GET /api/v1/forms/:id/fields/:fieldId/options

Returns options for a select/multi-select field that is backed by a dynamic data source (e.g., a data table column).

json
{
  "data": [
    { "value": "dept_eng", "label": "Engineering" },
    { "value": "dept_sales", "label": "Sales" },
    { "value": "dept_mkt", "label": "Marketing" }
  ]
}

Download File

GET /api/v1/forms/:id/files/:fileId

Returns the uploaded file as a binary download with the appropriate Content-Type header.


Public Endpoints

These endpoints require no authentication and are used for rendering and submitting public-facing forms.

Get Public Form

GET /api/v1/public/forms/:slug

Returns the form definition for rendering. Includes fields, branding, and settings but excludes internal metadata.

json
{
  "data": {
    "name": "Contact Form",
    "slug": "contact-form",
    "description": "General inquiries and feedback",
    "fields": [...],
    "branding": {
      "logo_url": "https://company.com/logo.png",
      "primary_color": "#4F46E5",
      "background_color": "#F9FAFB"
    },
    "settings": {
      "submit_button_text": "Send Message",
      "success_message": "Thank you!"
    }
  }
}

Public Submission

POST /api/v1/public/forms/:slug/submit
json
{
  "data": {
    "name": "Jane Smith",
    "email": "[email protected]",
    "message": "Hello, I'd like to learn more."
  }
}

Response:

json
{
  "data": {
    "submission_id": "sub_abc789",
    "status": "received"
  },
  "message": "Thank you! We'll get back to you soon."
}

Public File Upload

POST /api/v1/public/forms/:slug/upload

Upload a file as part of a public form submission. Use multipart/form-data.

FieldTypeRequiredDescription
filefileYesThe file to upload
field_idstringYesThe form field ID this file belongs to

Response:

json
{
  "data": {
    "file_id": "file_001",
    "filename": "resume.pdf",
    "size_bytes": 245000,
    "mime_type": "application/pdf"
  }
}

Include the returned file_id in the submission data object for the corresponding field.

Get Embed Code

GET /api/v1/public/forms/:slug/embed
json
{
  "data": {
    "script_embed": "<script src=\"https://forms.arcanflows.io/embed.js\" data-form-slug=\"contact-form\"></script>",
    "iframe_embed": "<iframe src=\"https://forms.arcanflows.io/f/contact-form?embed=true\" width=\"100%\" height=\"600\" frameborder=\"0\"></iframe>"
  }
}

Public Field Options

GET /api/v1/public/forms/:slug/fields/:fieldId/options

Same as the authenticated field options endpoint, but accessible without authentication for public form rendering.


Form Chat (Conversational Forms)

Conversational forms allow users to complete a form through a chat-like interface. An AI agent guides the user through each field conversationally.

Get Conversation

GET /api/v1/public/forms/:slug/conversations/:conversationId
json
{
  "data": {
    "id": "conv_abc123",
    "form_slug": "contact-form",
    "status": "active",
    "fields_completed": 2,
    "fields_total": 5,
    "collected_data": {
      "name": "John Doe",
      "email": "[email protected]"
    },
    "created_at": "2025-12-07T10:30:00Z"
  }
}

Get Messages

GET /api/v1/public/forms/:slug/conversations/:conversationId/messages
json
{
  "data": [
    {
      "id": "msg_001",
      "role": "assistant",
      "content": "Hi! I'd love to help you get in touch. What's your name?",
      "field_id": "name",
      "created_at": "2025-12-07T10:30:00Z"
    },
    {
      "id": "msg_002",
      "role": "user",
      "content": "John Doe",
      "created_at": "2025-12-07T10:30:15Z"
    },
    {
      "id": "msg_003",
      "role": "assistant",
      "content": "Nice to meet you, John! What's your email address?",
      "field_id": "email",
      "created_at": "2025-12-07T10:30:16Z"
    }
  ]
}

Send Message

POST /api/v1/public/forms/:slug/conversations/:conversationId/messages
json
{
  "content": "[email protected]"
}

Response:

json
{
  "data": {
    "user_message": {
      "id": "msg_004",
      "role": "user",
      "content": "[email protected]"
    },
    "assistant_message": {
      "id": "msg_005",
      "role": "assistant",
      "content": "Great! What topic is your inquiry about? You can choose: General Inquiry, Technical Support, or Sales Question.",
      "field_id": "subject"
    },
    "fields_completed": 2,
    "fields_total": 5,
    "form_completed": false
  }
}

When all fields are collected, the response indicates form completion:

json
{
  "data": {
    "user_message": { "id": "msg_010", "role": "user", "content": "Thanks!" },
    "assistant_message": {
      "id": "msg_011",
      "role": "assistant",
      "content": "Thank you, John! Your message has been submitted. We'll get back to you soon."
    },
    "fields_completed": 5,
    "fields_total": 5,
    "form_completed": true,
    "submission_id": "sub_xyz789"
  }
}

Stream Message

POST /api/v1/public/forms/:slug/conversations/:conversationId/messages/stream

Same request body as Send Message, but returns a Server-Sent Events (SSE) stream for the assistant response.


Data Table Integration

Forms can automatically save submissions to data tables. Configure this via the data_table_config field when creating or updating a form.

Configuration

json
{
  "data_table_config": {
    "table_id": "dt_contacts",
    "auto_save": true,
    "field_mapping": {
      "name": "full_name",
      "email": "email_address",
      "subject": "inquiry_type",
      "message": "body",
      "rating": "satisfaction_score"
    }
  }
}
FieldTypeDescription
table_idstringTarget data table ID
auto_savebooleanAutomatically insert a row on each submission
field_mappingobjectMaps form field IDs to data table column names

When auto_save is enabled, every new submission creates a row in the specified data table using the field mapping.


Field Configuration Examples

Select with Dynamic Data Source

json
{
  "id": "department",
  "type": "select",
  "label": "Department",
  "required": true,
  "data_source": {
    "type": "data_table",
    "table_id": "dt_departments",
    "value_column": "id",
    "label_column": "name"
  }
}

The options are loaded at render time via the /fields/:fieldId/options endpoint.

File Upload

json
{
  "id": "resume",
  "type": "file",
  "label": "Upload Resume",
  "required": true,
  "validation": {
    "allowed_types": ["pdf", "doc", "docx"],
    "max_size_mb": 10
  },
  "help_text": "PDF, DOC, or DOCX. Max 10MB."
}

Slider

json
{
  "id": "budget",
  "type": "slider",
  "label": "Monthly Budget",
  "required": true,
  "validation": { "min": 100, "max": 10000, "step": 100 },
  "help_text": "Drag to select your budget range"
}

Signature

json
{
  "id": "consent_signature",
  "type": "signature",
  "label": "Sign to Confirm",
  "required": true,
  "help_text": "Draw your signature above"
}

Conditional Field

json
{
  "id": "other_description",
  "type": "textarea",
  "label": "Please describe",
  "required": true,
  "conditional": {
    "field": "subject",
    "operator": "equals",
    "value": "other"
  }
}

Error Handling

All error responses follow a consistent format:

json
{
  "error": {
    "code": "validation_error",
    "message": "Form validation failed",
    "details": {
      "errors": [
        { "field": "email", "message": "Invalid email address" },
        { "field": "message", "message": "Must be at least 10 characters" }
      ]
    }
  }
}
HTTP StatusError CodeDescription
400validation_errorSubmission data failed validation
404form_not_foundForm does not exist or is not published
409form_not_publishedCannot submit to a draft or archived form
413file_too_largeUploaded file exceeds size limit
415unsupported_file_typeFile type not allowed
429rate_limit_exceededToo many submissions