AuthElement
A single-line OTP sign-in component. Customer types an email or phone number, presses submit, types the 6-digit code, and the Element emits an `authenticated` event with a Link session token. Use it standalone (e.g. on a login page) or alongside other Elements (the parent controller broadcasts the token to them automatically).
Iframe URL
https://link.cimplify.io/elements/auth?businessId=biz_…&nonce=<random>&email=<optional prefill>Authentication flow
- Element loads, posts
ready, parent replies withinit. - If a Link cookie is present on
link.cimplify.io, the Element silently re-authenticates and emitsauthenticatedimmediately. No user interaction needed. - Otherwise the customer enters a contact (email or phone). The Element posts to
POST /v1/link/elements/request-otpand emitsrequires_otp. - Customer types the 6-digit code. The Element posts to
POST /v1/link/elements/verify-otp; on success emitsauthenticatedwith the token, accountId, customerId, and customer profile.
React
import {
ElementsProvider,
AuthElement,
} from "@cimplify/sdk/react";
<ElementsProvider client={client}>
<AuthElement
prefillEmail="jane@example.com"
onReady={() => setReady(true)}
onRequiresOtp={({ contactMasked }) => setStatus(`Code sent to ${contactMasked}`)}
onAuthenticated={({ token, accountId, customerId, customer }) => {
setToken(token);
setCustomer(customer);
}}
onError={(err) => setError(err.message)}
/>
</ElementsProvider>Props
| Prop | Type | Notes |
|---|---|---|
className / style | Applied to the wrapper <div> hosting the iframe. | |
prefillEmail | string | Pre-fills the contact field. |
onReady | () => void | iframe interactive. |
onRequiresOtp | (d: { contactMasked }) => void | OTP dispatched. |
onAuthenticated | (d: AuthenticatedData) => void | Token + customer. |
onError | (err: { code, message }) => void | Any failure. |
AuthenticatedData
interface AuthenticatedData {
accountId: string;
customerId: string;
token: string;
customer: { name: string; email: string | null; phone: string | null };
}Vanilla
import { createElements, ELEMENT_TYPES, EVENT_TYPES } from "@cimplify/sdk";
const elements = createElements(client, businessId);
const auth = elements.create(ELEMENT_TYPES.AUTH, { prefillEmail: "jane@…" });
auth.on(EVENT_TYPES.AUTHENTICATED, (data) => {
// data: AuthenticatedData
setToken(data.token);
});
auth.on(EVENT_TYPES.REQUIRES_OTP, ({ contactMasked }) => {
setStatus(`Code sent to ${contactMasked}`);
});
auth.mount("#auth-container");Standalone iframe
<iframe
src="https://link.cimplify.io/elements/auth?businessId=biz_…&nonce=ab12cd34"
style="border:0; width:100%; min-height:160px"
sandbox="allow-scripts allow-same-origin allow-forms"
></iframe>Test mode
When publicKey begins with pk_test_, the Element pre-fills +233200000001 as the contact and shows a banner. Use the test phone numbers and OTP 123456 documented under environments.
Logout
Send { type: "logout" } from the parent. The Element clears its session cookie via POST /v1/link/elements/logout and emits logout_complete.
What it does NOT do
- No social sign-in (Google / Apple / Facebook). OTP only.
- No magic-link email. The verification is always a 6-digit code.
- No password fallback.
- No biometric / WebAuthn step. Trust is rooted in possession of the contact channel.
Next
- CheckoutElement: Auth + address + payment in one iframe
- SDK auth reference: Programmatic OTP without the iframe
Universal Commerce Protocol (UCP)
A signed, capability-discoverable protocol AI agents use to browse, price, check out, and pay across any Cimplify business with verifiable consent.
CheckoutElement
The full unified checkout iframe. Auth, address, payment method, and submit all live in one frame. This is the iframe behind `<CimplifyCheckout>` and the hosted Pay page, sharing the same code at `packages/link/src/pages/elements/checkout/`.