Calls
Fetch job openings, grant calls, and any other application-driven opportunity. Apply via the call's embedded form.
- Use it for: Public website · Server integration
- Reads: public token — works in the browser
- Writes: none — read-only today
- CLI:
uidu calls - Auth: what each token can do and where it may run — Authentication
A call is anything in uidu that accepts applications: a job opening, a grant call, a residency, a casting call. Each one carries its own application form, so a call page is a rich-text body plus a form to submit. For job postings and their first-class applications, see Jobs & applications.
Mental model
Call ← listCalls (summaries) / getCall (full)
├─ kind 'job' | 'open_call' | 'opportunity'
├─ body, cover rich text (Tiptap JSON) and cover image URL
├─ quantity number of openings
├─ salaryMin / salaryMax whole currency units
├─ expiresAt the application deadline
├─ primaryAddress for location-bound calls
└─ form the application form — same shape as getForm()
└─→ FormResponse createFormResponse (Forms domain)- One primitive, three kinds.
kindisjob,open_calloropportunity.listCallsreturns all of them; filter onkindyourself, or uselistJobsforjobonly. - The list is a summary.
listCallsreturnsid,name,cover,kind,status,quantity, salaries,publishedAt,expiresAt,publicUrl,publicPath,publishedand a shortprimaryAddress(formattedAddress,city). There is nobodyand noform: fetch one call withgetCallfor those. - The form is inlined.
getCallselectscall.formwith the sameFormFieldsfragment asgetForm, socall.formgoes straight into<DynamicForm>or any renderer you wrote for Forms. Each question is atcall.form.inputs.edges[].node. - Salaries are whole units, not cents — unlike every other amount in uidu (see
Data model). Both are
number | null. The call's currency is not part of the SDK's selection, so pass it yourself when you format (formatSalaryRange). - No deadline filter.
listCallstakes onlyfirst/afterand sends no filter, so filter onexpiresAtyourself if the page should list open calls only. - The calls domain is read-only. Applying is a write in another domain: submit the call's
form with
createFormResponse, or, for a job, record an application withcreateApplication. Either way it runs in a server action with theapiKeyclient — see Authentication.
Use cases
The examples import uidu from lib/uidu.ts, a client built with publicToken and apiKey
and imported only from server code, as in Authentication.
Listing open calls
Goal: a page that lists every call still accepting applications, with its place and deadline.
// app/calls/page.tsx
import { listCalls } from '@uidu/client';
import { uidu } from '@/lib/uidu';
export default async function CallsPage() {
const calls = await listCalls(uidu, { first: 50 });
const now = new Date();
const open = calls
.filter((c) => c.kind !== 'job') // jobs have their own careers page
.filter((c) => !c.expiresAt || new Date(c.expiresAt as string) > now)
.sort((a, b) =>
String(a.expiresAt ?? '').localeCompare(String(b.expiresAt ?? '')),
);
return (
<ul>
{open.map((call) => (
<li key={call.id}>
<a href={`/calls/${encodeURIComponent(call.id)}`}>{call.name}</a>
{call.primaryAddress?.city && ` · ${call.primaryAddress.city}`}
{call.expiresAt &&
` · apply by ${new Date(call.expiresAt as string).toLocaleDateString()}`}
</li>
))}
</ul>
);
}listCallsreturns one page as a flat array (empty if none). To read every call, passListCallsDocumenttopaginate— see Pagination & field values.- Call ids are GlobalIDs: encode them in a URL and decode them in the route, as above.
Open-call page with its application form
Goal: one call's page — body, deadline, and the application form, submitted from the server.
// app/calls/[id]/page.tsx
import { getCall, createFormResponse } from '@uidu/client';
import { DynamicForm, RichText, type DynamicFormValues } from '@uidu/react';
import { notFound } from 'next/navigation';
import { uidu } from '@/lib/uidu';
export default async function CallPage({
params,
}: {
params: Promise<{ id: string }>;
}) {
const { id } = await params;
const call = await getCall(uidu, { id: decodeURIComponent(id) });
if (!call) notFound();
const form = call.form;
const formId = form?.id;
async function apply(values: DynamicFormValues) {
'use server';
if (!formId)
return { ok: false as const, errors: [{ name: 'No application form' }] };
const result = await createFormResponse(uidu, {
input: {
attributes: {
formId,
fieldValuesAttributes: values.fieldValues.map((fv) => ({
fieldId: fv.fieldId,
content: { value: fv.value }, // always wrapped
})),
contactAttributes: values.contact && {
email: values.contact.email,
contactableAttributes: {
kind: 'person',
firstName: values.contact.firstName,
lastName: values.contact.lastName || undefined,
},
},
},
event: 'complete!', // submit it, don't leave a draft
},
});
return result?.errors?.length
? { ok: false as const, errors: result.errors }
: { ok: true as const, meta: { responseId: result?.formResponse?.id } };
}
return (
<article>
<h1>{call.name}</h1>
{call.expiresAt && (
<p>
Apply by {new Date(call.expiresAt as string).toLocaleDateString()}
</p>
)}
{call.body && <RichText doc={call.body} />}
{form && <DynamicForm form={form} action={apply} submitLabel="Apply" />}
</article>
);
}getCallreturnsnullfor an unknown id;call.formcan benulltoo (a call that takes no applications).<DynamicForm>collects the candidate's first name, last name and email (includeContactFields, on by default) plus one value per visible question.createFormResponsedoesn't throw on validation errors: checkerrors. A transport failure throws aUiduError— see Errors.- Attachments (CV, portfolio): each media question carries its upload target at
call.form.inputs.edges[].node.field—uploadPresignedUrlis a presigned POST as JSON ({ url, fields }), split intouploadUrlanduploadParams; follow the file upload flow. - For a call of kind
job, record a first-class application instead, so it shows up on the call's board: Job page with an apply form.
API at a glance
Every @uidu/client function in Calls, generated from the source — the full reference has the rest of the SDK.
| Function | Kind | Auth | CLI | Description |
|---|---|---|---|---|
getCall | read | public token | calls get | One call (a job opening or open call) with its application form, same shape as getForm, or null. |
listCalls | read | public token | calls list | The workspace's calls as a flat array of summaries, without their forms; page with first/after. |
Types: Call
CLI:
| Entity | list | get | create | update | delete |
|---|---|---|---|---|---|
calls | ✓ | ✓ | — | — | — |