Back to Blog
Engineering4 min read

Webhook Best Practices for Reliable Form Delivery

With a webhook form, your endpoint is the destination for a response. That gives you control over where it lives, but it also makes your receiver's behavior part of the user's form experience. Here is a short checklist to test before sending real submissions.

Verify the signed headers

SingleForm sends X-SingleForm-Signature, X-SingleForm-Timestamp, X-SingleForm-Nonce, and X-SingleForm-Form-Id when submission authentication is available. The HMAC-SHA256 signature covers {formId}.{timestamp}.{nonce} with your webhook secret. It does not cover the request body. Use HTTPS for transport integrity and confidentiality, and treat signature verification as one control rather than a body checksum.

The Express, Python, and Rails packages handle the signature and timestamp check. Here is the Express shape:

import express from "express";
import { singleform } from "singleform-express-webhook";

const app = express();
app.use(express.json());

app.post(
  "/webhooks/singleform",
  singleform({ secret: process.env.SINGLEFORM_SECRET }),
  async (req, res) => {
    const submissionId = await saveSubmission(req.body);
    res.singleformSuccess({ submissionId, message: "Received" });
  }
);

Keep the secret on your server. Do not expose it in a website or mobile bundle. If you implement verification yourself, reject stale timestamps and compare signatures in constant time. A timestamp only limits the replay window; to reject a duplicate within that window, your receiver must remember a used nonce or enforce idempotency using its own durable key. The current Express middleware validates the signature and timestamp but does not keep a nonce store for you.

Respond quickly and clearly

Finish any work needed to make the submission durable, then return a response promptly. If you queue later work, make sure the queue accepted the job before you report success. Otherwise a 200 can tell the user the response was received when it was actually lost.

SingleForm can show a structured error to the person submitting the form. For example:

{
  "success": false,
  "error": {
    "type": "DUPLICATE_SUBMISSION",
    "message": "This email is already registered"
  }
}

Use a message the person can act on. Keep personal data out of error text and logs. The response format also supports field-level validation errors.

Handle duplicates and failures

There are no server-side retries: SingleForm does not retain a submission body for later redelivery. Your receiver should still be idempotent, because users can submit twice and networks can leave the sender unsure whether the first attempt succeeded. Choose a stable key for your own workflow and make a repeat safe.

Monitor your endpoint's availability and SingleForm's delivery status. Test at least three paths before launch: a success response, a validation error, and an unavailable endpoint. If a failed submission matters to your workflow, make sure the person submitting knows what to do next.

Follow the quick start to build a test receiver, or create a form and point it at your own endpoint.