Every TruForms form has an access key — a UUID you get from the dashboard. Paste it into any of the snippets below and you're done. The access key is public; it only identifies the form. Never put your session cookies or Razorpay keys in client code.
New here? The flow is always the same: (1) create a form in the dashboard, (2) copy its access key, (3) drop one of the snippets below into your site. No SDK to install, no build step, no server code.
HTML
The simplest integration — no JavaScript at all. The browser POSTs the form, our endpoint returns a 303 redirect (if you set one in Settings) or a JSON response.
<form action="https://forms.truenotech.com/api/submit" method="POST">
<input type="hidden" name="access_key" value="YOUR_ACCESS_KEY" />
<label>Name <input type="text" name="name" required /></label>
<label>Email <input type="email" name="email" required /></label>
<label>Message <textarea name="message" required></textarea></label>
<!-- Honeypot: hidden from users, filled only by bots -->
<input type="text" name="botcheck" style="display:none" tabindex="-1" autocomplete="off" />
<button type="submit">Send</button>
</form>
fetch (vanilla JavaScript)
const form = document.querySelector('#contact');
form.addEventListener('submit', async (e) => {
e.preventDefault();
const data = Object.fromEntries(new FormData(form));
const res = await fetch('https://forms.truenotech.com/api/submit', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ access_key: 'YOUR_ACCESS_KEY', ...data }),
});
const result = await res.json();
if (result.success) {
form.reset();
alert('Message sent.');
} else {
alert(result.message);
}
});
React
import { useState } from 'react';
export function ContactForm() {
const [status, setStatus] = useState('idle');
async function onSubmit(e) {
e.preventDefault();
setStatus('sending');
const body = new FormData(e.currentTarget);
body.append('access_key', 'YOUR_ACCESS_KEY');
const res = await fetch('https://forms.truenotech.com/api/submit', {
method: 'POST',
body,
});
const result = await res.json();
setStatus(result.success ? 'sent' : 'error');
}
return (
<form onSubmit={onSubmit}>
<input name="name" required />
<input name="email" type="email" required />
<textarea name="message" required />
<input name="botcheck" type="text" style={{ display: 'none' }} />
<button disabled={status === 'sending'}>{status === 'sent' ? 'Thanks!' : 'Send'}</button>
</form>
);
}
Next.js (App Router)
Same React component. If you want server-side handling, route the submission through a Route Handler that proxies to /submit — but there's no need to add server code just to hit our endpoint.
Astro
---
// src/pages/contact.astro
---
<form action="https://forms.truenotech.com/api/submit" method="POST">
<input type="hidden" name="access_key" value="YOUR_ACCESS_KEY" />
<input name="name" required />
<input name="email" type="email" required />
<textarea name="message" required></textarea>
<input type="text" name="botcheck" style="display:none" />
<button>Send</button>
</form>
Vue
<script setup>
async function submit(e) {
e.preventDefault();
const body = new FormData(e.target);
body.append('access_key', 'YOUR_ACCESS_KEY');
const res = await fetch('https://forms.truenotech.com/api/submit', {
method: 'POST',
body,
});
const result = await res.json();
console.log(result);
}
</script>
<template>
<form @submit="submit">
<input name="name" required />
<input name="email" type="email" required />
<textarea name="message" required />
<button>Send</button>
</form>
</template>
File uploads
Send the form as multipart/form-data (the default when the form has an <input type="file">). Files are stored in object storage; signed 7-day download links are included in notification emails.
<form action="https://forms.truenotech.com/api/submit" method="POST" enctype="multipart/form-data">
<input type="hidden" name="access_key" value="YOUR_ACCESS_KEY" />
<input name="name" required />
<input name="email" type="email" required />
<input type="file" name="attachment" />
<button>Send</button>
</form>
Per-form limits (max file size, allowed extensions, max count) are configurable in the form's Settings tab.
Captcha
Add the site key in Settings → Security, then include the widget in your markup:
<!-- Cloudflare Turnstile -->
<script src="https://challenges.cloudflare.com/turnstile/v0/api.js" async defer></script>
<div class="cf-turnstile" data-sitekey="YOUR_SITE_KEY"></div>
The hidden input cf-turnstile-response is auto-added by Cloudflare and forwarded to us. Our backend verifies it server-side using your stored secret key before the submission is accepted.
See the Captcha guide for hCaptcha, React/Vue wrappers, error codes, and dev test keys.
Redirect after submit
Set a Redirect URL in the form's Settings, or pass redirect in the payload:
<input type="hidden" name="redirect" value="https://yoursite.com/thanks" />
If present, the response is a 303 See Other to that URL. Otherwise the response is JSON: { success: true, submissionId: "..." }.
Further reading
- MDN — Fetch API — the
fetchcalls used in the snippets above. - MDN —
FormData— how the multipart/file examples build their body. - MDN —
multipart/form-data— the encoding used for file uploads. - MDN — HTTP
303 See Other— the redirect-after-submit behavior.