All public endpoints are served at https://api.vlozi.app/forms/f/… and require no authentication. The form_id in the URL is the only credential.
Submit
POST /f/:form_id
Accepts application/json (AJAX / SDK) and application/x-www-form-urlencoded / multipart/form-data (plain HTML <form>). Any field not listed in the reserved fields below is stored verbatim in the submission.
Rate limit: 20 requests per 60 seconds per IP address.
Reserved fields
These fields are handled by the service and are not stored in the submission data:
| Field | Purpose |
|---|---|
botcheck (or your form's honeypot field) |
Spam trap — fill this and the submission is silently discarded |
cf-turnstile-response |
Turnstile token (required if CAPTCHA is enabled on the form) |
redirect |
URL to 303-redirect to on success (plain HTML form posts only) |
access_key |
Ignored — vlozi uses the URL form_id instead |
Success response (200)
{
"success": true,
"message": "Thank you! Your submission has been received.",
"data": {
"email": "visitor@example.com",
"message": "Hello!"
}
}For plain HTML form posts with a redirect field or a form-level redirectUrl → the server responds with 303 to that URL instead.
File fields in the response
When a submission includes files, each file field in data becomes a structured object:
{
"resume": {
"__file": true,
"name": "resume.pdf",
"size": 184320,
"type": "application/pdf",
"url": "https://cdn.vlozi.app/…/resume.pdf"
}
}Error responses
| Status | When |
|---|---|
400 |
Validation failed — { success: false, message: "Validation failed", errors: { fieldErrors, formErrors } } |
400 |
CAPTCHA failed — { success: false, message: "Captcha verification failed" } |
402 |
Tenant has run out of credits |
403 |
Your site's origin is not in the form's allowed origins |
403 |
The form is paused |
404 |
Form not found, deleted, or archived |
429 |
Rate limit exceeded — slow down |
Schema
GET /f/:form_id/schema
Returns the public form definition. Use this if you are building your own form UI.
{
"id": "form_abc123",
"name": "Contact Us",
"schema": {
"fields": [
{
"name": "email",
"type": "email",
"label": "Email address",
"required": true
},
{
"name": "message",
"type": "textarea",
"label": "Message",
"required": true
}
]
},
"successMessage": "Thanks! We'll be in touch.",
"captchaRequired": false,
"settings": {
"theme": {
"accent": "#FF5436",
"buttonLabel": "Send"
},
"turnstileSiteKey": null
}
}404 if the form is deleted or archived.
Field types
| Type | Notes |
|---|---|
text |
Plain text; optional pattern (regex), min/max (character length) |
email |
Validated as a valid email address |
tel |
Phone number; optional pattern |
url |
Validated as a valid URL |
number |
Numeric; optional min/max (value range) |
textarea |
Multi-line text; optional min/max (character length) |
select |
Single-choice dropdown; requires options: string[] |
checkbox |
Boolean; value stored as "true" or "false" |
date |
ISO 8601 date string (e.g. "2026-06-28") |
file |
Up to 5 files per submission; max 25 MB each |
@vlozi/forms SDK
Types
interface FormSchema {
fields: FormField[];
}
interface FormField {
name: string;
type: "text" | "email" | "tel" | "url" | "number" | "textarea"
| "select" | "checkbox" | "date" | "file";
label?: string;
placeholder?: string;
help?: string;
required?: boolean;
min?: number;
max?: number;
pattern?: string;
options?: string[];
}
interface SubmitResult {
success: boolean;
message: string;
data?: Record<string, unknown>;
errors?: {
fieldErrors: Record<string, string[]>;
formErrors: string[];
};
}createFormClient(opts)
const form = createFormClient({
formId: string,
baseUrl?: string, // default: "https://api.vlozi.app/forms"
});form.getSchema()
Fetches the public schema. Returns FormSchema.
form.submit(data)
Submits the form. Accepts a plain object or a FormData instance (use FormData for file uploads). Returns SubmitResult. Never throws on 4xx/5xx — only network errors throw.