CoDuck Docs

#Forms

Capture submissions from any form (contact, waitlist, feedback) without writing a backend. Submitting is browser-safe; reading requires the API key, so it runs on the server.

ts
import { forms } from '@coduck/sdk/forms';
import { forms } from '@coduck/sdk/forms';

#Submit (browser-safe)

submit() is public — call it from a client component. It only needs NEXT_PUBLIC_CODUCK_PROJECT_ID (injected at deploy).

tsx
'use client';
import { forms } from '@coduck/sdk/forms';

async function onSubmit(e: React.FormEvent<HTMLFormElement>) {
  e.preventDefault();
  const data = new FormData(e.currentTarget);
  await forms.submit('contact', {
    name: data.get('name'),
    email: data.get('email'),
    message: data.get('message'),
  });
}
'use client';
import { forms } from '@coduck/sdk/forms';

async function onSubmit(e: React.FormEvent<HTMLFormElement>) {
  e.preventDefault();
  const data = new FormData(e.currentTarget);
  await forms.submit('contact', {
    name: data.get('name'),
    email: data.get('email'),
    message: data.get('message'),
  });
}

You can also import the bound helper directly:

ts
import { submit } from '@coduck/sdk/forms';
await submit('waitlist', { email });
import { submit } from '@coduck/sdk/forms';
await submit('waitlist', { email });

The formName is just a label you choose — submissions are grouped by it.

#Read submissions (server only)

list() and markRead() require CODUCK_API_KEY, so call them from a route handler or server component.

ts
import { forms } from '@coduck/sdk/forms';

const recent = await forms.list({ formName: 'contact', limit: 50 });
await forms.markRead(recent[0].id);
import { forms } from '@coduck/sdk/forms';

const recent = await forms.list({ formName: 'contact', limit: 50 });
await forms.markRead(recent[0].id);
MethodScopeReturns
submit(formName, fields)browser-safevoid
list({ formName?, limit? })serverFormSubmission[]
markRead(id)serverFormSubmission

Submissions also show up in your project's Forms tab in the cloud panel.

#Type

ts
interface FormSubmission {
  id: string;
  projectId: string;
  formName: string;
  fields: Record<string, unknown>;
  submitterIp: string | null;
  userAgent: string | null;
  read: boolean;
  createdAt: string;
}
interface FormSubmission {
  id: string;
  projectId: string;
  formName: string;
  fields: Record<string, unknown>;
  submitterIp: string | null;
  userAgent: string | null;
  read: boolean;
  createdAt: string;
}