Reference

FORX documentation

FORX turns any form or event into a production-ready endpoint. Point a form at your endpoint URL, and FORX validates, stores, and forwards every submission.

Quickstart

Create an endpoint in the dashboard, then point your form at the generated URL. No SDK required.

HTML
<form action="https://forx.dev/f/abc123" method="POST">
  <input name="email" type="email" required />
  <textarea name="message"></textarea>
  <button type="submit">Send</button>
</form>
fetch
await fetch("https://forx.dev/f/abc123", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ email: "dev@example.com", message: "Hello" })
})

Endpoints

Every endpoint follows the same shape: {origin}/f/{id}. The id is generated when you create the endpoint and never changes.

MethodPathPurpose
POST/f/:idSubmit a form or JSON payload
GET/f/:idEndpoint health and accepted fields

Both application/json and application/x-www-form-urlencoded bodies are accepted.

Payloads

Successful submissions return the stored event so you can confirm the shape immediately.

201 Created
{
  "id": "evt_01H8XA",
  "endpoint": "contact-form",
  "created_at": "2024-03-12T14:22:01Z",
  "data": {
    "email": "dev@example.com",
    "message": "Hello from FORX"
  }
}

Webhooks

FORX signs every delivery with an X-Forx-Signature header (HMAC SHA-256 of the raw body) and retries failed deliveries three times with backoff.

Verification
import { createHmac, timingSafeEqual } from "node:crypto"

const digest = createHmac("sha256", process.env.FORX_WEBHOOK_SECRET!)
  .update(rawBody)
  .digest("hex")

const valid = timingSafeEqual(Buffer.from(digest), Buffer.from(signature))
Next.js route handler
export async function POST(request: Request) {
  const rawBody = await request.text()
  const signature = request.headers.get("X-Forx-Signature")

  if (!verifyForxSignature(rawBody, signature)) {
    return Response.json({ error: "invalid_signature" }, { status: 401 })
  }

  const event = JSON.parse(rawBody)
  if (event.type === "user.submit") {
    await createUser(event.data)
  }

  return Response.json({ received: true })
}

Event types include user.submit, submission.created, and submission.failed.

Billing

FORX has a free plan for getting started, plus Pro for teams that need more capacity. Free includes 1,000 submissions, 1 endpoint, 1 webhook destination, and 1-day retention. Pro is $10 per month and unlocks 100,000 submissions, unlimited endpoints and webhooks, 90-day retention, automations, and team seats.

LimitFree — $0Pro — $10
Submissions / month1,000100,000
Active endpoints1Unlimited
Webhook destinations1Unlimited + retries
Data retention1 day90 days
AutomationsNot includedIncluded
Team membersNot includedIncluded

Bachs does not publish a public API reference, so checkout is not wired into this app yet — the plan surface in Settings is ready for it once their API details are available.

Errors

StatusCodeMeaning
404endpoint_not_foundNo endpoint exists for that id
422invalid_payloadRequired fields missing or malformed
429rate_limitedPlan submission limit reached