Backend
Client and hooks
pleate-client has two entry points. pleate-client is framework free: createPleateClient(), errors, list and SSE helpers, and the generated types. pleate-client/react adds a provider and hooks built on TanStack Query, each returning a …Props object to spread on a pleate component.
createPleateClient
import { createPleateClient } from "pleate-client";
const client = createPleateClient({
baseUrl: "/api",
locale: () => document.documentElement.lang,
onUnauthorized: () => location.assign("/login"),
});
const me = await client.auth.me();
const page = await client.files.list({ search: "receipt", ordering: "-created_at" });
for await (const event of client.ai.send(conversationId, { content: "Hello" })) {
if (event.event === "delta") process.stdout.write(event.data.text);
}Options
| Option | Default | Meaning |
|---|---|---|
| baseUrl | "/api" | Where pleate-backend is mounted. An absolute URL works too. |
| fetch | globalThis.fetch | Custom fetch: tests, or forwarding cookies on the server. |
| credentials | "include" | So the session cookie also travels on cross origin setups. |
| headers | none | Extra headers, or a function returning them. E.g. { Authorization: "Bearer pl_..." }. |
| locale | none | Sent as Accept-Language. A string or a function. |
| csrf | { cookieName: "csrftoken", headerName: "X-CSRFToken", path: "/csrf" } | false for API key clients. |
| onUnauthorized | none | Called on every 401. |
Modules
| Module | Methods |
|---|---|
| auth | csrf, me, updateMe, signup, login, logout, changePassword, requestPasswordReset, validateResetToken, resetPassword, verifyEmail, resendVerification, changeEmail, confirmEmailChange, uploadAvatar, removeAvatar, exportData, preferences, updatePreferences, deleteAccount |
| sessions | list, revoke, revokeOthers |
| mfa | status, setup, confirm, disable, regenerateBackupCodes, verify |
| oauth | providers, startUrl (a URL to navigate to), accounts, unlink |
| apiKeys | list, create, rename, revoke |
| files | list, get, upload (with onProgress), rename, remove, usage, downloadUrl, presign, complete |
| notifications | list, unreadCount, markRead, markUnread, markAllRead, remove, clearRead, preferences, updatePreferences, stream (SSE), pushPublicKey, subscribePush, unsubscribePush |
| ai | models, suggestions, usage, conversations, createConversation, conversation, updateConversation, deleteConversation, messages, send (SSE), stop, regenerate (SSE) |
| billing | plans, subscription, checkout, portal |
| marketing | subscribe, confirmSubscription, unsubscribe, contact, joinWaitlist, waitlistStatus |
| activity | mine, all, get |
| webhooks | events, endpoints, createEndpoint, updateEndpoint, deleteEndpoint, rotateSecret, test, deliveries, delivery, redeliver |
| rbac | myFeatures, roles, createRole, updateRole, deleteRole, permissions, assignRole, removeRole, features |
| staff | users, user, updateUser, deleteUser, revokeSessions, sendPasswordReset, stats, bans, createBan, deleteBan |
| usage | summary |
| search(q, { types, limit, signal }) | The signed in user's files, conversations and notifications → SearchResult[]. |
| list<T>(path, params) | Any list endpoint of your own that follows the conventions → Page<T>. |
| http | The underlying Http: get, post, put, patch, delete, raw, stream, upload, url, ensureCsrf. |
Every method returns typed data and throws ApiError (status, code, fields, fieldErrors(), retryAfter) on failure. Streams are async generators of {event, data}; pass an AbortSignal to stop them. Types for every schema are available as Schema<"Me">, plus named aliases: Me, Session, ApiKey, FileItem, Notification, Conversation, ChatMessage, Plan, ActivityLog, StaffUser...
Helpers
| Export | Does |
|---|---|
| isApiError(error, code?) | Type guard, optionally for one code. |
| toOrdering(sort) / fromOrdering(ordering) | Between {key, direction} and -price. |
| toSearchParams(params) | Query string without empty values, arrays repeated. |
| parseSse(body, signal) | Parses any text/event-stream body (fetch, POST included). |
React
<PleateProvider options={{ baseUrl: "/api" }}> {/* or client={client} queryClient={queryClient} */}
<App />
</PleateProvider>The provider creates the client and a QueryClient (30 second stale time, no retries on 401) unless you pass yours. usePleateClient() returns the client for calls without a hook; keys holds the query keys, so you can invalidate them (queryClient.invalidateQueries({ queryKey: keys.apiKeys })).
Hooks
| Hook | Returns | For |
|---|---|---|
| useMe() | user, isSignedIn, hasRole, hasPermission, hasFeature, query state | Any component |
| useUpdateMe() | mutation, updates the cached user | Profile forms |
| useLogin({ onSuccess }) | loginFormProps, twoFactorFormProps, mfaRequired, reset, login, verify | LoginForm, TwoFactorForm |
| useSignup({ onSuccess }) | signupFormProps, verificationRequired, signup | SignupForm |
| useLogout({ onSuccess }) | mutation, clears the cache | Any button |
| useForgotPassword() | forgotPasswordFormProps | ForgotPasswordForm |
| useResetPassword(token, { onSuccess }) | resetPasswordFormProps, tokenValid, checkingToken | ResetPasswordForm |
| useVerifyEmail(token) | query of the verified user | Verification page |
| useTwoFactorSetup({ onDone }) | twoFactorSetupProps (after start), start, starting, status, enabled, disable | TwoFactorSetup |
| useOAuth({ next, mode, remember }) | oauthButtonsProps, providers query | OAuthButtons |
| useSocialAccounts() | accounts query, unlink | Linked accounts list |
| useSessions() | sessionListProps | SessionList |
| useApiKeys() | apiKeyListProps | ApiKeyList |
| useList(path | fn, options) | tableProps, paginationProps, searchProps, sortProps(key), rows, setters | DataTable, Table, SearchBar, Pagination |
| useCursorList(key, fetcher, options) | items, fetchNextPage, hasNextPage | Feeds, List |
| useUpload({ purpose, onUploaded }) | fileUploadProps, uploaded, busy, add, remove, retry, clear | FileUpload |
| useNotifications({ live, pageSize, unreadOnly }) | notificationCenterProps, unreadCount, markRead, markAllRead, remove | NotificationBell, NotificationCenter |
| usePushSubscription() | mutation taking a ServiceWorkerRegistration | Push opt in |
| useChat(id | null, { model, onConversation }) | composerProps, messages, streaming, error, send, stop, regenerate, loadOlder | ChatThread, Message, Composer |
| useModels(initial?) | modelPickerProps, model, setModel | ModelPicker |
| useSuggestions(onSelect) | promptSuggestionsProps | PromptSuggestions |
| useConversations({ archived }) | useList result for conversations | Chat sidebar |
| useAiUsage() | query of today's tokens | Quota meter |
| usePreferences() | preferences, update (optimistic, rolls back on error) | Theme and bottom bar settings |
| useUsage() | plan, items, usageMeterProps | UsageMeter |
| useSearch(q, { types, limit }) | results, query state; runs from 2 characters | Command palette |
| usePricing({ isSignedIn, signInHref, renderCta }) | pricingProps, billing, setBilling, checkout, portal | Pricing |
| useSubscription() | subscription, openPortal | Billing settings |
| useNewsletter({ source }) | newsletterProps, confirmationRequired | Newsletter |
| useContactForm() | contactFormProps | ContactForm |
| useWaitlist() | mutation returning position and referral code | Waitlist form |
Every hook also spreads the underlying TanStack Query result (data, isPending, error, refetch...) or exposes its mutations, for anything the props do not cover.
Errors in forms
errorProps(error) turns any failure into the error and fieldErrors props every pleate form takes: field messages go under their inputs, everything else above the form. mapFields renames backend fields to form fields.
import { errorProps, mapFields } from "pleate-client/react";
const save = useMutation({ mutationFn: client.auth.changePassword });
<PasswordForm
onSubmit={(v) => save.mutate({ current_password: v.current, new_password: v.next })}
{...mapFields(errorProps(save.error), { current_password: "current", new_password: "next" })}
/>