Webhooks integration

Form Webhooks for Developers

Webhooks push each completed Ovoform submission to an endpoint you control the moment it is saved. You get a JSON body, optional HMAC-SHA256 signing, custom headers, automatic retries and a delivery log, so you can wire a form into any backend without polling an API.

No credit card required. Unlimited responses. Webhooks are available on every plan.

What you can do with Ovoform and Webhooks

Deliver

JSON to your endpoint on every response

Each completed submission is sent as an HTTP request to the URL you set. Choose POST or PUT and add any custom headers, such as an API key your endpoint expects.

Sign

Requests you can verify

Set a secret and Ovoform signs every request with HMAC-SHA256 over a timestamp and the body, so your endpoint can confirm the request came from Ovoform and reject replays.

Retry

Automatic retries when your endpoint is down

If your endpoint returns an error or times out, Ovoform tries again, up to three attempts in total, so a short outage does not lose submissions.

Inspect

A delivery log for every attempt

See what was sent, the status your endpoint returned, the response body and how long it took. It is the first place to look when something does not arrive.

How the Webhooks connection works

  1. Create an HTTPS endpoint

    Stand up a URL that accepts JSON and answers with a 2xx status quickly. Private and internal addresses are blocked for safety.

  2. Add the webhook to your form

    In the form's Workflow tab, add a webhook with the URL, the method, any headers and, if you want signing, a secret.

  3. Verify a real submission

    Submit the form and check the delivery log. Verify the signature in your code against the raw request body.

  4. Handle failures

    Return a 2xx once you have stored the data. Anything else is treated as a failure and retried.

Full setup guide

Ways teams use Webhooks with Ovoform

Push leads into your own CRM

Receive each lead as JSON and create the record in an internal system that has no off-the-shelf connector.

Lead generation templates

Start fulfillment from an order

Have an order form call your fulfillment service directly, with the answers ready to turn into a job or shipment.

Order form template

Feed an applicant tracking system

Send job applications to your hiring tool's API so candidates appear without anyone re-entering them.

Job application form template

Need to read data, not just receive it?

Webhooks push submissions out as they happen. If you would rather pull forms and responses on demand, or build an integration that people sign in to, the Ovoform developer documentation covers the API and OAuth. The MCP server lets AI assistants read forms and responses too.

Explore the developer docs

What syncs, and what to know

Each completed response is saved first and delivered afterwards, so respondents never wait on your endpoint. A delivery counts as successful only when your endpoint answers with a 2xx status. Any other status, and any network error or timeout, is retried: three attempts in total, with the retries arriving roughly 30 seconds and 90 seconds after a failure. The default timeout is 30 seconds. Return a response quickly and do heavy work afterwards.

Signing is optional and uses a secret you choose, which is not generated for you. Without a secret, requests are sent unsigned. The Send test button in the form's Workflow tab sends a sample payload with a different shape that is not signed, so check your signature code against a real submission and its entry in the delivery log rather than against the test. Ovoform blocks private and internal URLs when you create the webhook and again at delivery time.

The delivery log records each request's URL, headers and payload, the status your endpoint returned, the first part of its response body, the latency and any error. Because retries are delivered as separate attempts, expect to see several entries for one response when your endpoint is failing. Deliveries can arrive more than once, so make your handler idempotent by keying on the response ID. Workflows also have a separate webhook action that can run only when conditions match. Those requests are not signed.

Payload

Each delivery is a JSON body describing one completed response. Answers are listed with the ID of the question they belong to.

{
  "id": "resp_8f3a1c",
  "formId": "form_2b7d90",
  "answers": [
    { "questionId": "q_123", "value": "Ada Lovelace" },
    { "questionId": "q_124", "value": "ada@example.com" }
  ],
  "createdAt": "2026-09-25T09:41:07.000Z"
}

IDs and values here are illustrative. Value shapes depend on the question type, so inspect a real delivery in the log for your form.

Verify the signature

When a secret is set, each request carries X-Webhook-Signature, X-Webhook-Timestamp (milliseconds since the epoch) and X-Webhook-Signature-Version, which is v1. The signature is the hex HMAC-SHA256 of the timestamp, a dot and the raw body.

import { createHmac, timingSafeEqual } from 'node:crypto';

const MAX_AGE_MS = 5 * 60 * 1000;

export function isValidOvoformRequest(rawBody, headers, secret) {
  const signature = headers['x-webhook-signature'];
  const timestamp = headers['x-webhook-timestamp'];
  if (!signature || !timestamp) return false;
  if (headers['x-webhook-signature-version'] !== 'v1') return false;

  const age = Date.now() - Number(timestamp);
  if (!Number.isFinite(age) || Math.abs(age) > MAX_AGE_MS) return false;

  const expected = createHmac('sha256', secret)
    .update(timestamp + '.' + rawBody)
    .digest('hex');

  const received = Buffer.from(signature);
  const wanted = Buffer.from(expected);
  return received.length === wanted.length && timingSafeEqual(received, wanted);
}

Hash the raw request body exactly as received, before any JSON parsing, and reject requests older than five minutes to block replays.

Connect Ovoform to Webhooks today

Build your first form, connect Webhooks in a couple of minutes, and start receiving responses where you work.

Prefer AI? Connect via our MCP server.