Skip to main content

Tenant API

The tenant router manages the current tenant's profile and settings. Every authenticated user belongs to an organization (tenant) resolved from their Clerk session.

Router namespace: tenant

Source: src/server/trpc/routers/tenant.ts

Procedures

ProcedureTypeAccessDescription
getCurrentquerytenantGet the current tenant record
updateSettingsmutationadminUpdate tenant settings

getCurrent

Returns the full tenant record for the authenticated user's organization. The tenant is resolved from the Clerk orgId via the hasTenant middleware.

tenant.getCurrent.queryOptions()

Input

None.

Response

{
"id": "tenant_789",
"clerkOrgId": "org_abc123",
"name": "Acme Corporation",
"slug": "acme-corp",
"plan": "professional",
"settings": {
"defaultScoringInterval": "daily",
"notificationsEnabled": true,
"timezone": "America/New_York"
},
"createdAt": "2026-01-15T08:00:00.000Z",
"updatedAt": "2026-03-05T10:00:00.000Z"
}

Returns null if the tenant record cannot be found (this should not occur under normal conditions since the middleware auto-provisions tenants).

Example

import { useTRPC } from "@/lib/trpc";
import { useQuery } from "@tanstack/react-query";

function TenantHeader() {
const trpc = useTRPC();
const { data: tenant } = useQuery(trpc.tenant.getCurrent.queryOptions());

return (
<header>
<h1>{tenant?.name}</h1>
<span className="badge">{tenant?.plan}</span>
</header>
);
}

updateSettings

Updates the tenant's settings object. Accepts a free-form JSON record that replaces the existing settings.

tenant.updateSettings.mutationOptions(options)

Access: Admin only

Input

FieldTypeRequiredDescription
settingsRecord<string, unknown>YesNew settings object (replaces existing)

Response

Returns the updated tenant record:

{
"id": "tenant_789",
"clerkOrgId": "org_abc123",
"name": "Acme Corporation",
"slug": "acme-corp",
"plan": "professional",
"settings": {
"defaultScoringInterval": "weekly",
"notificationsEnabled": false,
"timezone": "America/Los_Angeles"
},
"createdAt": "2026-01-15T08:00:00.000Z",
"updatedAt": "2026-03-05T12:00:00.000Z"
}
Full Replacement

The settings field is replaced entirely, not merged. Always include all settings keys when updating to avoid losing existing values.

Example

const trpc = useTRPC();
const queryClient = useQueryClient();

const mutation = useMutation(
trpc.tenant.updateSettings.mutationOptions({
onSuccess: () => {
queryClient.invalidateQueries({
queryKey: trpc.tenant.getCurrent.queryKey(),
});
},
})
);

// Read current settings first, then merge
const currentSettings = queryClient.getQueryData(
trpc.tenant.getCurrent.queryKey()
)?.settings ?? {};

mutation.mutate({
settings: {
...currentSettings,
defaultScoringInterval: "weekly",
},
});
tip

Always read the current settings before updating to avoid accidentally overwriting existing values. The pattern above shows how to merge new settings with existing ones.

Tenant Schema

The tenant record contains these fields:

FieldTypeDescription
idstringInternal tenant identifier (UUID)
clerkOrgIdstringClerk organization ID
namestringOrganization display name
slugstringURL-safe organization slug
planstringSaaS plan tier
settingsRecord<string, unknown>Free-form tenant settings
createdAtDateTenant creation timestamp
updatedAtDateLast update timestamp