Build the auth flow
Drive email OTP, onboarding, readiness, routing, and sign-out from one identity state.
@capxul/sdk-react exposes one canonical identity state and one stable auth
facade. Your application owns forms, copy, routes, and invocation IDs.
Before you start
Mount CapxulProvider with a working
publishable key. Choose requirement="deployed" if the signed-in journey must
claim a deployed personal account.
Read the journey
import { useCapxulAuth, useCapxulDestination, useCapxulIdentity } from "@capxul/sdk-react";
function AuthState() {
const identity = useCapxulIdentity();
const destination = useCapxulDestination();
const auth = useCapxulAuth();
if (identity.phase === "signed_out") {
return <EmailForm onSubmit={(email) => auth.requestCode(email)} />;
}
if (identity.phase === "otp_pending") {
return <OtpForm onSubmit={(otp) => auth.verifyCode(otp)} />;
}
if (
identity.phase === "otp_sending" ||
identity.phase === "otp_verifying" ||
identity.phase === "signing_out"
) {
return <Pending />;
}
if (identity.phase === "faulted") {
return <Failure code={identity.failure.code} />;
}
return <SignedIn destination={destination} onSignOut={() => auth.signOut()} />;
}Every expected facade failure resolves { ok: false, reason }. It does not
reject. Pass caller-owned controls as the optional final argument:
await auth.verifyCode(otp, {
correlationId: crypto.randomUUID(),
journeyId,
timeoutMs: 15_000,
signal,
});Use app-owned slots
CapxulAuthenticationController
implements the same exhaustive phase selection without rendering SDK markup:
<CapxulAuthenticationController
slots={{
email: EmailSlot,
otp: OtpSlot,
pending: PendingSlot,
failure: FailureSlot,
success: SuccessSlot,
}}
/>Complete onboarding
For a personal journey call auth.completePersonal(profileDetails, options).
For the current Organization journey, use
CapxulOnboardingController.
It preserves Profile → Organization submit → account claim → Organization
creation while your app retains the controlled form and submitted-request
carrier.
<CapxulOnboardingController
intent={intent}
organizationProfile={organizationProfile}
submittedOrganization={submittedOrganization}
onIntent={setIntent}
onOrganizationProfile={setOrganizationProfile}
onSubmittedOrganization={setSubmittedOrganization}
navigation={navigation}
slots={slots}
/>Retry actions receive fresh app-owned correlationId values while retaining
the journey ID. The controller never creates either identifier.
Route and sign out
useCapxulDestination() returns a descriptor or null; map it to your own
routes. Successful auth.signOut() clears the authenticated query boundary.
The identity state then becomes signed_out.
Agent-native
What agent-native means on this platform — agents doing what users and developers can do, through safe structured primitives, and docs built for machine readers.
Work with organizations
List the orgs a user belongs to, create one, switch the acting entity, read treasury/members/roles, and invite a member with a role.