Build with Forms.
REST API, webhooks, and embedded workflows. Everything you need to ship.
Bearer keys.
Every request carries a workspace-scoped API key in the Authorization header. Mint keys from /settings/api. Keys are shown once, then stored as SHA-256 digests — don’t lose them, rotate if you do.
curl -H "Authorization: Bearer frmk_live_3a8f..." \
https://forms.inversify.live/api/v1/forms/frm_7x2k9p/submissionsMissing or malformed headers return 401. Keys that don’t belong to the target form’s workspace return 403.
Post a response.
Submit answers to a published form. Field IDs come from the form schema (visible in the builder’s “Embed” tab). Unknown fields are rejected, required fields are enforced, types are coerced.
POST https://forms.inversify.live/api/v1/forms/frm_7x2k9p/submissions
Authorization: Bearer frmk_live_3a8f...
Content-Type: application/json
{
"answers": {
"fld_name": "Ada Lovelace",
"fld_email": "ada@analytical.engine",
"fld_rating": 9,
"fld_notes": "Loved the conversational flow."
}
}HTTP/1.1 201 Created
Content-Type: application/json
{
"id": "res_01HX9M2KQ4",
"formId": "frm_7x2k9p",
"completedAt": "2026-04-21T17:42:08.314Z"
}On success, a response.created webhook event fans out to every subscribed endpoint for that form.
Signed events.
Configure endpoints per form under Form → Integrations. Each delivery carries an HMAC-SHA256 signature of the raw body in X-Inversify-Signature. Verify before you trust.
- response.createdFired immediately when any response is saved (form, chat, or API).
- response.analyzedFired after open-text answers have been themed and sentiment-scored.
{
"event": "response.created",
"formId": "frm_7x2k9p",
"deliveryId": "dlv_01HX9M...",
"timestamp": "2026-04-21T17:42:08.314Z",
"data": {
"id": "res_01HX9M2KQ4",
"answers": { "fld_name": "Ada Lovelace", "fld_rating": 9 },
"source": "api"
}
}import crypto from "node:crypto";
export function verify(rawBody: string, signature: string, secret: string) {
const expected = crypto
.createHmac("sha256", secret)
.update(rawBody)
.digest("hex");
// timing-safe compare
const a = Buffer.from(expected, "hex");
const b = Buffer.from(signature, "hex");
return a.length === b.length && crypto.timingSafeEqual(a, b);
}
// in your handler:
const raw = await req.text();
const sig = req.headers.get("x-inversify-signature") ?? "";
if (!verify(raw, sig, process.env.FORM_WEBHOOK_SECRET!)) {
return new Response("bad signature", { status: 401 });
}Deliveries retry with exponential backoff for up to 24 hours on any non-2xx response. Each attempt carries the same deliveryId so you can dedupe cleanly.
Rate limits.
Quotas are per API key, per form. Exceeded requests return 429 with a Retry-After header.
Need higher ceilings? Team plans raise submission throughput to 2,000 / 60s by default — email hi@inversify.live.