# JavaScript SDK

Use `@form2n8n/sdk` when you want your own HTML and JavaScript instead of the rendered widget.

The SDK is not published to npm yet. Until it is, call the submit endpoint directly (below) — it's one `fetch` call.

## Without the SDK

The submit endpoint is public and CORS-enabled, so any page can post to it:

javascript:

```js
const res = await fetch('https://form2wf.com/api/v1/submit/3f1c…form-uuid', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ name: 'Ada', email: 'ada@example.com' })
});
const result = await res.json();
// 200: { "success": true, "data": <n8n response>, "message": "Submitted successfully" }
// 403 inactive form · 429 quota or rate limit · 502 n8n failed or timed out
```

Send JSON for plain values, or `FormData` for file uploads (see [multipart payloads](https://form2wf.com/docs/webhooks#multipart)). Submissions are rate-limited to 10 per minute per IP.

## SDK setup

javascript:

```js
import { Form2n8n } from '@form2n8n/sdk';

const f2 = new Form2n8n({
  apiUrl: 'https://form2wf.com/api/v1',   // always set this — the built-in default is a placeholder
  onError: (err) => console.error(err)
});
```

SDK methods take the form's **UUID** (shown in the dashboard URL and returned by `list_forms`), not its slug.

## submit

```
const result = await f2.submit('3f1c…form-uuid', {
  name: 'Ada',
  email: 'ada@example.com',
  message: 'Hello'
});
// result = whatever your n8n workflow responded with
```

The object you pass becomes `data` in the [submit payload](https://form2wf.com/docs/webhooks#submit). Unlike the widget, the SDK returns n8n's response body, so you can show a result computed by your workflow.

## bindForm

Wire your own `<form>` element: submission is intercepted and sent as a flat object of its named inputs.

```
<form id="signup">
  <input name="email" type="email" required>
  <button>Join</button>
</form>
<script type="module">
  f2.bindForm(document.getElementById('signup'), '3f1c…form-uuid', {
    onSuccess: () => alert('Subscribed!'),
    onError: (e) => alert(e.message)
  });
</script>
```

## fetch and poll

`fetch(formId)` calls the form's submit webhook with an empty POST and returns `data` from n8n's reply — handy for small read-only feeds. `poll(formId, callback, intervalMs)` repeats it and returns a function that stops polling.

```
const items = await f2.fetch('7b9e…form-uuid');
const stop = f2.poll('7b9e…form-uuid', (items) => render(items), 10000);
// later: stop();
```

`fetch` doesn't forward query parameters to n8n and doesn't check login. For parameterized or per-user data, use a form with an [onload webhook](https://form2wf.com/docs/data-pages#onload) instead.

## Form-user auth

```
await f2.auth.login('client@acme.com', 'password', '<organization-id>');
f2.auth.isAuthenticated(); // true
await f2.submit('3f1c…', { request: 'Reset router' }, { auth: true });
f2.auth.logout();
```

## Reference

| Member | Description |
| --- | --- |
| `new Form2n8n({ apiUrl, onError })` | Create a client. |
| `submit(formId, data, { auth, headers })` | Submit data; resolves to n8n's response. |
| `fetch(formId, { auth })` | Call the form's webhook for data. |
| `bindForm(el, formId, { auth, headers, onSuccess, onError })` | Handle a form element's submit event. |
| `poll(formId, callback, intervalMs, options)` | Repeat `fetch`; returns a stop function. |
| `auth.login / register / logout / isAuthenticated / getToken` | Form-user session helpers. |

---
Source: https://form2wf.com/docs/sdk — Form2Workflow documentation (Publishing)
