Skip to Content
Webhook Response Format

Webhook Response Format

Your webhook endpoint must return JSON in one of the standard formats below. SingleForm parses the response and displays appropriate messages to the user in the mobile app.

Success Response

Return this when the submission was processed successfully:

{ "success": true, "data": { "submissionId": "your-internal-id-123", "message": "Thank you for your submission!" } }
FieldTypeRequiredDescription
successtrueYesMust be true for success responses.
data.submissionIdstringRecommendedYour system’s ID for this submission. Used to link SingleForm analytics to your records.
data.messagestringNoDisplayed to the user in the mobile app.
data.*anyNoAdditional data is stored but not displayed.

Error Response

Return this for business logic errors that aren’t tied to specific fields:

{ "success": false, "error": { "type": "DUPLICATE_SUBMISSION", "message": "This email is already registered for this event" } }
FieldTypeRequiredDescription
successfalseYesMust be false for error responses.
error.typestringYesError type code (see Standard Error Types below).
error.messagestringYesHuman-readable message displayed to the user.

Validation Error Response

Return this when specific form fields have validation errors. SingleForm highlights the invalid fields in the mobile app:

{ "success": false, "error": { "type": "VALIDATION_FAILED", "message": "Please correct the highlighted fields", "fields": { "email": "Invalid email format", "phone": "Phone number must be 10 digits" } } }
FieldTypeRequiredDescription
error.typestringYesMust be "VALIDATION_FAILED" for field-level errors.
error.fieldsobjectYesKeys are field names, values are error messages.

Standard Error Types

Security Errors (returned by the middleware)

These are returned automatically by the Express middleware when signature verification fails. You don’t need to handle these yourself if you’re using the SDK.

TypeHTTP StatusDescription
MISSING_HEADERS401Required SingleForm headers are missing
INVALID_TIMESTAMP401Timestamp is not a valid number
TIMESTAMP_EXPIRED401Request is older than the tolerance window
INVALID_SIGNATURE401Signature format is invalid
SIGNATURE_MISMATCH401Signature doesn’t match the expected value

Business Logic Errors (returned by your code)

Use these standard types for common scenarios:

TypeRecommended StatusDescription
VALIDATION_FAILED400Field-level validation errors. Include the fields object.
DUPLICATE_SUBMISSION400A duplicate entry was detected (e.g., same email).
RATE_LIMITED429Too many submissions from this user/IP.

Custom Error Types

You can define your own error types for business-specific logic:

// Custom error types res.singleformError("EVENT_FULL", "This event has reached maximum capacity"); res.singleformError("REGISTRATION_CLOSED", "Registration is no longer open"); res.singleformError("PROCESSING_ERROR", "Unable to process. Please try again.", 500);

SingleForm will display the message to the user regardless of the error type.

HTTP Status Codes

StatusMeaningWhen to Use
200SuccessSubmission processed successfully
400Bad RequestValidation or business logic error
401UnauthorizedSignature verification failed (handled by middleware)
429Too Many RequestsRate limit exceeded
500Server ErrorUnexpected server-side error

How SingleForm Handles Your Response

ResponseWhat Happens
success: trueShows success message to user. Records submissionId in analytics.
success: false with VALIDATION_FAILEDHighlights the invalid fields with error messages in the form.
success: false with other typesShows the error message to the user.
Non-JSON responseShows a generic error to the user.
Timeout (30s)Shows a timeout error. The submission may have been processed on your end.

TypeScript Types

If you’re using TypeScript, the canonical types are available in @singleform/shared:

interface WebhookSuccessResponse { success: true; data: { submissionId?: string; message?: string; [key: string]: any; }; } interface WebhookErrorResponse { success: false; error: { type: string; message: string; fields?: { [fieldName: string]: string }; }; } type WebhookResponse = WebhookSuccessResponse | WebhookErrorResponse;

The Express middleware SDK also exports these types — see Exported Types.

Examples Using the Express SDK

import { singleform } from "@singleform/express-webhook"; app.post( "/webhooks/singleform", singleform({ secret: process.env.SINGLEFORM_SECRET }), async (req, res) => { const { email, firstName } = req.body; // Validation error if (!email) { return res.singleformValidationError({ email: "Email is required", }); } // Duplicate check const existing = await db.findByEmail(email); if (existing) { return res.singleformError( "DUPLICATE_SUBMISSION", "This email is already registered" ); } // Success const record = await db.create({ email, firstName }); res.singleformSuccess({ submissionId: record.id, message: "Registration complete!", }); } );