Documentation

Better Form API

Use Better Form as a hosted form backend: submit responses externally, receive webhook alerts, and fetch response data with separate API keys.

Base URL
https://betterform.dev/api
Submission key
bf_sub_... for external writes and webhook signatures.
Data key
bf_data_... for read-only response exports.

Endpoints

Submit responses
POST /submit/{publicId}

Send response payloads from your own frontend or server.

Webhook delivery
POST your webhook URL

Receive real-time response notifications signed with your submission key.

Fetch responses
GET /forms/data/{dataApiKey}

Export response data in JSON with lightweight rate limiting.

Submission API

Authenticate with Authorization: Bearer {submissionApiKey} and send a responses object keyed by field IDs.

fetch("https://betterform.dev/api/submit/{publicId}", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "Authorization": "Bearer bf_sub_your_submission_key_here"
  },
  body: JSON.stringify({
    responses: {
      field_name: "Ada Lovelace",
      field_email: "ada@example.com"
    }
  })
})

Webhook verification

Better Form includes an `X-BetterForm-Signature` header for each webhook request. Verify it before trusting the payload.

import crypto from "crypto"

function verifyWebhook(payload, signature, submissionApiKey) {
  const expected = crypto
    .createHmac("sha256", submissionApiKey)
    .update(JSON.stringify(payload))
    .digest("hex")

  return signature === expected
}

Response export API

Use the data key in the path. Responses are rate limited to one request every five seconds per form.

fetch("https://betterform.dev/api/forms/data/{dataApiKey}", {
  headers: { Accept: "application/json" }
})
  .then((res) => res.json())
  .then((data) => console.log(data.responses))