---
name: forminit-nodejs
description: Integrates Forminit headless form backend into Node.js applications using the npm SDK with server-side API key. Submits forms with typed blocks (sender, text, email, phone, file, rating, date, select, radio, checkbox, country, number). Use when handling form submissions from Node.js, Express, Fastify, or any server-side JavaScript. Do not use for Next.js (use forminit-nextjs), Nuxt.js (use forminit-nuxtjs), or client-side HTML (use forminit-html).
metadata:
  author: forminit
  version: "1.0"
---

# Forminit — Node.js Integration

> Forminit is a headless form backend API. You build the form UI, Forminit handles submission, validation, storage, and notifications. This skill uses the npm SDK on the server side.

## Constraints

- Server-side only. API key must be in environment variables, never in client code.
- User must set authentication mode to "Protected" in Form settings before creating an API token.
- All field names use prefix pattern: `fi-{type}-{name}`
- Sender block: max 1 per form. Use for submitter's contact info.
- Default to `fi-sender-firstName` + `fi-sender-lastName`. Use `fi-sender-fullName` only if user wants a single name field.
- For non-submitter emails/phones/countries, use field blocks: `fi-email-invitee`, `fi-phone-emergency`, `fi-country-shipping`
- File uploads require FormData (not JSON)
- Max 50 blocks per form, max 25 MB total files

## Install

```bash
npm install forminit@latest
```

## Environment Variable

```bash
# .env
FORMINIT_API_KEY="YOUR-SECRET-API-TOKEN"
```

## Basic Submission (JSON)

```js
import { Forminit } from 'forminit';

const forminit = new Forminit({
  apiKey: process.env.FORMINIT_API_KEY,
});

const { data, error } = await forminit.submit('FORM_ID', {
  blocks: [
    {
      type: 'sender',
      properties: {
        firstName: 'Jane',
        lastName: 'Doe',
        email: 'jane@example.com',
      },
    },
    { type: 'text', name: 'message', value: 'Hello from Node.js' },
  ],
});

if (error) {
  console.error(error.message);
} else {
  console.log('Submitted:', data.hashId);
}
```

Replace `FORM_ID` with the form ID from https://app.forminit.com.

## Express Example

```js
import express from 'express';
import { Forminit } from 'forminit';

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

const forminit = new Forminit({
  apiKey: process.env.FORMINIT_API_KEY,
});

app.post('/submit', async (req, res) => {
  const { data, error } = await forminit.submit('FORM_ID', {
    blocks: req.body.blocks,
  });

  if (error) return res.status(error.code).json({ error: error.message });
  res.json({ id: data.hashId });
});

app.listen(3000);
```

## FormData Submission (for file uploads)

```js
import { Forminit } from 'forminit';

const forminit = new Forminit({
  apiKey: process.env.FORMINIT_API_KEY,
});

const formData = new FormData();
formData.append('fi-sender-email', 'jane@example.com');
formData.append('fi-text-message', 'Hello');
formData.append('fi-file-resume', fileBuffer, 'resume.pdf');

const { data, error } = await forminit.submit('FORM_ID', formData);
```

## Form Blocks Reference

### Sender Block — `fi-sender-{property}`

One per form. Collects submitter info. At least one property required.

```
fi-sender-email        fi-sender-firstName    fi-sender-lastName     fi-sender-fullName
fi-sender-phone        fi-sender-company      fi-sender-position     fi-sender-title
fi-sender-userId       fi-sender-address      fi-sender-city         fi-sender-country
```

### Field Blocks — `fi-{type}-{name}`

Each name must be unique. Up to 50 total blocks.

```
text      fi-text-{name}       e.g. fi-text-message
number    fi-number-{name}     e.g. fi-number-quantity
email     fi-email-{name}      e.g. fi-email-invitee
phone     fi-phone-{name}      e.g. fi-phone-emergency          Validation: E.164 (+12025550123)
url       fi-url-{name}        e.g. fi-url-website
date      fi-date-{name}       e.g. fi-date-appointment         Validation: ISO 8601 (YYYY-MM-DD)
rating    fi-rating-{name}     e.g. fi-rating-satisfaction      Validation: integer 1-5
select    fi-select-{name}     e.g. fi-select-plan              Supports multi-select (string[])
radio     fi-radio-{name}      e.g. fi-radio-priority           Single choice (string)
checkbox  fi-checkbox-{name}   e.g. fi-checkbox-features        Supports multi-choice (string[])
file      fi-file-{name}       e.g. fi-file-resume              Add [] for multiple: fi-file-photos[]
country   fi-country-{name}    e.g. fi-country-shipping         Validation: ISO 3166-1 alpha-2
```

## SDK Response

```js
const { data, redirectUrl, error } = await forminit.submit(formId, payload);
```

Success: `data.hashId` (submission ID), `data.date`, `data.blocks` (submitted values), `redirectUrl` (thank-you page URL).

Error: `error.error` (code like `FI_SCHEMA_FORMAT_EMAIL`), `error.code` (HTTP status), `error.message` (human-readable).

## Common Mistakes

- Using `name="email"` instead of `fi-sender-email` — all fields must use the `fi-` prefix or the submission will be empty.
- Using `fi-sender-name` — there is no `name` property on sender. Use `fi-sender-firstName` + `fi-sender-lastName` or `fi-sender-fullName`.
- Putting the API key in client-side code — the key must stay on the server.
- Setting form authentication to "Public" instead of "Protected" — Node.js integration requires Protected mode.
- Sending phone without E.164 format — `5551234567` will be rejected, must be `+15551234567`.
- Using JSON with file uploads — files only work with FormData.

## Documentation

- Full guide: https://forminit.com/docs/nodejs/
- SDK reference: https://forminit.com/docs/sdk/
- Form blocks: https://forminit.com/docs/form-blocks/

## Spam Protection (only if user requests)

- reCAPTCHA: https://forminit.com/docs/recaptcha/
- hCaptcha: https://forminit.com/docs/hcaptcha/
