TryMellon
Navigation

API Reference

Condensed reference for the public SDK API and types.

API Reference

Condensed reference for the TryMellon JavaScript SDK public API.

TryMellon

Main entry point. Create a client with your app configuration. Prefer TryMellon.create() so invalid config returns a Result instead of throwing.

import { TryMellon } from '@trymellon/js';

const clientResult = TryMellon.create({
  appId: 'YOUR_APP_ID',
  publishableKey: 'cli_xxxx',
});
if (!clientResult.ok) throw clientResult.error;
const client = clientResult.value;

TryMellonConfig

NameTypeDescription
appIdstring (required)Application ID from the TryMellon dashboard.
publishableKeystring (required)Client ID (safe for the browser). Starts with cli_.
apiBaseUrlstringOverride the API base URL. Default: 'https://api.trymellonauth.com'.
timeoutMsnumberHTTP request timeout (ms). Range 1000–300000. Default: 30000.
maxRetriesnumberRetries for transient errors. Range 0–10. Default: 3.
retryDelayMsnumberDelay between retries (ms). Range 100–10000. Default: 1000.
loggerLoggerCustom logger. Default: console.
sandboxbooleanIf true, signUp/signIn return immediately with a fixed token. See Sandbox mode.
sandboxTokenstringCustom token in sandbox mode. Default: the exported SANDBOX_SESSION_TOKEN constant.
enableTelemetrybooleanOpt-in anonymous event tracking. Default: false.
telemetrySenderTelemetrySenderCustom telemetry sender. Overrides the default HTTP sender when enableTelemetry is true.
telemetryEndpointstringCustom endpoint for the default telemetry sender.
originstringOverride the Origin header sent with API requests. Useful in SSR or non-browser environments where window.location.origin is unavailable.
contextHashStorage{ getItem, setItem }Custom storage for the context hash. Defaults to sessionStorage. Override in environments where sessionStorage is unavailable (e.g. React Native, SSR).
preset'saas' | 'web3'Opt-in surface gate. Default 'saas' exposes the core passkey API. 'web3' additionally exposes client.identity.* and client.siwe.* (F1). Any other value returns INVALID_ARGUMENT. Types narrow based on the preset — 'saas' hides the web3 namespaces at compile time.
customClaimsRecord<string, string | number | boolean>Opt-in custom claims injected into the session JWT under the namespace https://trymellon.dev/claims. Max 10 keys / 2 KB; each key must match the custom_claims_schema configured on the application.

Static methods

MethodReturnsDescription
TryMellon.create(config)Result<TryMellon, TryMellonError>Factory — validates config and returns a client. Preferred over the constructor.
TryMellon.isSupported()booleantrue if the browser supports WebAuthn.

Deprecated: new TryMellon(config) — throws on invalid config instead of returning a Result. Use TryMellon.create(config) instead.

signUp(options?)

Registers a new passkey for the user. Returns a Result with sessionToken on success.

const result = await client.signUp({ externalUserId: 'user_123' });

RegisterOptions

NameTypeDescription
externalUserIdstringYour external user identifier. Optional for anonymous registration; backend returns external_user_id in init/validation.
authenticatorType'platform' | 'cross-platform'Authenticator preference.
successUrlstringRedirect URL after success (must be in allowlist).
signalAbortSignalCancel the operation.
external_user_idstringDeprecated. Use externalUserId instead.

RegisterResult

NameTypeDescription
successtrueAlways true on success.
credentialIdstringThe new passkey credential ID.
statusstringAlways 'registered' on success.
sessionTokenstringSession token — send to your backend.
userobject{ userId, externalUserId?, email?, metadata? }
redirectUrlstring?Set when successUrl was passed and allowed.

signIn(options?)

Authenticates the user with an existing passkey. Returns a Result with sessionToken on success.

const result = await client.signIn({ externalUserId: 'user_123' });

AuthenticateOptions

NameTypeDescription
externalUserIdstringYour external user identifier.
hintstringCredential hint for the browser.
successUrlstringRedirect URL after success.
signalAbortSignalCancel the operation.
mediation'optional' | 'conditional' | 'required'WebAuthn mediation preference.
external_user_idstringDeprecated. Use externalUserId instead.

AuthenticateResult

NameTypeDescription
authenticatedbooleantrue on success.
sessionTokenstringSession token — send to your backend.
userobject{ userId, externalUserId?, email?, metadata? }
signalsobject?{ userVerification?, backupEligible?, backupStatus? }
redirectUrlstring?Set when successUrl was passed and allowed.

session.verify(sessionToken)

Client-side check: validates a session token against the API. Returns a Result indicating whether the session is valid. You must pass the token; the SDK does not read cookies. See Session validation.

const result = await client.session.verify(sessionToken);
if (result.ok && result.value.valid) {
  // Session is valid
}

SessionValidateResponse

Fields are camelCase in the SDK response. The raw REST API returns snake_case fields nested in a data envelope — see Backend validation for the raw HTTP contract.

NameTypeDescription
validbooleanWhether the session is valid.
userIdstringTryMellon user ID.
externalUserIdstringYour external user ID.
tenantIdstringTenant ID.
appIdstringApplication ID.

session.verifyOffline(sessionToken)

Offline JWT validation — verifies the RS256 signature and claims locally against the JWKS exposed at /.well-known/jwks.json. No network round-trip per call; the JWKS is cached for 1 hour. Available since SDK v3.4.0. See Backend validation for when to prefer offline vs remote.

const result = await client.session.verifyOffline(sessionToken);
if (result.ok) {
  console.log(result.value.userId, result.value.customClaims);
}

Runs on WebCrypto. RS256 is locked — any other algorithm is rejected. Clock skew tolerance is ±30 s. The namespace https://trymellon.dev/claims is flattened into the top-level customClaims field.

SessionClaims

NameTypeDescription
userIdstringTryMellon user ID.
externalUserIdstring?Your external user ID.
tenantIdstringTenant ID.
appIdstringApplication ID.
iat / expnumberIssued-at / expires-at (Unix seconds).
kidstringRFC 7638 thumbprint of the signing key.
customClaimsRecord<string, unknown>?Flattened from https://trymellon.dev/claims when present.

capabilities()

Returns the client’s WebAuthn environment status. Use to decide whether to offer passkey or email fallback.

const status = await client.capabilities();

ClientStatus

NameTypeDescription
isPasskeySupportedbooleanWhether the browser supports WebAuthn.
platformAuthenticatorAvailablebooleanWhether a platform authenticator (e.g. Touch ID) is available.
recommendedFlow'passkey' | 'fallback'Recommended auth flow based on environment.

on(event, callback)

Subscribe to SDK events (e.g. for loading spinners or analytics). Returns an unsubscribe function.

const unsub = client.on('success', (payload) => {
  console.log(payload.operation, payload.token);
});
// later: unsub();

Events: start, success, error, cancelled. See Events & Error handling.

otp

Email OTP fallback when WebAuthn is not available.

MethodReturnsDescription
otp.send({ userId, email })Promise<Result<void>>Sends OTP to the given email. userId is your external user id.
otp.verify({ userId, code, successUrl? })Promise<Result<{ sessionToken, redirectUrl? }>>Verifies the code and returns a session token.

See Fallback by email.

identity

Link and unlink secondary identifiers (email, wallet) on a signed-in user. Available only when preset: 'web3' — on a 'saas' client the namespace is absent at compile time. userId is implicit: resolved from the current session. Calling any method without an active session returns INVALID_ARGUMENT.

MethodReturnsDescription
identity.linkEmail({ email })Promise<Result<{ challengeId }>>Starts an email-link challenge. Sends a one-time code to email; finalize with verifyEmailLink.
identity.verifyEmailLink({ challengeId, code })Promise<Result<{ identifierId }>>Completes the link. Emits identifier.linked webhook.
identity.list()Promise<Result<{ identifiers: Identifier[] }>>Lists all identifiers bound to the current user (type: 'email' | 'wallet' | 'custom').
identity.unlink({ identifierId })Promise<Result<void>>Removes an identifier. Emits identifier.unlinked webhook.

See Identity linking.

siwe

Sign-In with Ethereum (EIP-4361). Available only when preset: 'web3'. prepareMessage is a pure helper — zero dependencies, safe to call outside a session. verifyAndSignIn issues a session token after signature verification.

MethodReturnsDescription
siwe.getNonce({ address, chainId })Promise<Result<{ nonce, expiresAt }>>Fetches a server-issued nonce. chainId must be in the application’s allowed_chain_ids allowlist.
siwe.prepareMessage(params)stringBuilds an EIP-4361 message from { domain, address, statement?, uri, version, chainId, nonce, issuedAt, ... }. Pure function — no network. Also exported standalone as prepareSiweMessage from @trymellon/js/web3.
siwe.verifyAndSignIn({ message, signature })Promise<Result<{ sessionToken, user }>>Verifies the signature, finds-or-creates the user bound to the wallet address, and returns a session token.

See SIWE login.

crossDevice

Cross-device authentication (QR login). Desktop initiates, mobile approves.

MethodReturnsDescription
crossDevice.start()Promise<Result<CrossDeviceInitResult>>Creates a cross-device session. Returns { session_id, qr_url, expires_at, polling_token }.
crossDevice.startRegistration(options?)Promise<Result<...>>Creates a cross-device registration session. options.externalUserId is optional — omit for anonymous registration.
crossDevice.waitForCompletion(sessionId, signal?, pollingToken?)Promise<Result<...>>Blocks until the mobile device approves. Returns { status, sessionToken, userId, redirectUrl? }. sessionToken and userId are only present when status === 'completed' — which is the only case this resolves successfully (timeout/abort return an error).
crossDevice.getContext(sessionId)Promise<Result<CrossDeviceContextResult>>Gets session context (used on the mobile side).
crossDevice.approve(sessionId)Promise<Result<...>>Approves the cross-device session from the mobile device.

See Cross-device auth.

enroll(options)

Enrolls a device or entity using a single-use ticket issued by your backend. Used for the Entity Enrollment (Keys & Padlock) flow.

const result = await client.enroll({ ticketId: 'ticket_xxx' });
if (result.ok) {
  console.log('Session token:', result.value.sessionToken);
  console.log('Credential:', result.value.credentialId);
}
NameTypeDescription
ticketIdstring (required)Enrollment ticket ID issued by your backend via POST /v1/enrollment/tickets.
signalAbortSignalCancel the operation.

EnrollmentResult

NameTypeDescription
sessionTokenstringSession token — send to your backend.
credentialIdstringThe new passkey credential ID.
userIdstringTryMellon user ID for the enrolled entity.
entityIdstring?Entity ID bound to the credential (when issued with one).

Returns Result<EnrollmentResult, TryMellonError>. See Entity Enrollment.

getContextHash()

Returns the context hash bound to the current browser session. This hash ties an enrollment ticket to a specific client context — pass it when issuing a ticket from your backend so replay on a different origin fails.

const contextHash = client.getContextHash();
// Send to your backend when requesting a ticket

Returns string (64-char hex, SHA-256). Persisted in sessionStorage for the duration of the session.

bridge

Bridge flows for QR-based enrollment and authentication from a second device (e.g. mobile scanning a desktop QR).

MethodReturnsDescription
bridge.getContext(sessionId, kind)Promise<Result<BridgeContextResponse>>Gets the bridge session context. kind: 'enrollment' or 'auth'.
bridge.verifyPresence(sessionId, pin, kind)Promise<Result<BridgeChallengeResponse>>Verifies the presence PIN and returns WebAuthn options.
bridge.complete(sessionId, options?)Promise<Result<BridgeResult>>Completes the ceremony. options.kind ('enrollment' or 'auth') is required. For enrollment: options.ticketId (ticket ID) and options.entityId are also required. Optionally pass options.presencePin or options.onPinRequired if PIN was not already verified.
bridge.waitForResult(sessionId, options?)Promise<Result<BridgeStatusSnapshot>>Polls or listens via SSE until the bridge session reaches a terminal state.

See Cross-device auth and Entity Enrollment.

passkey.recover(options)

Recovers an account using an email OTP and creates a new passkey. Requires server-side initiation first.

const result = await client.passkey.recover({
  externalUserId: 'user_123',
  otp: '632145',
});
NameTypeDescription
externalUserIdstring (required)The external user ID.
otpstring (required)The 6-digit OTP from the recovery email.

Returns Result<RecoverAccountResult, TryMellonError>. See Account Recovery.

Wire format note: The SDK sends external_id (not external_user_id) to the recovery endpoint — a historical field preserved for backend compatibility. Pass externalUserId in your SDK call as usual; the conversion is automatic.

version()

Returns the SDK version string.

console.log(client.version()); // e.g. '3.0.0'

SANDBOX_SESSION_TOKEN

Exported constant — the fixed token returned in sandbox mode. Use it in your backend to identify sandbox sessions during development.

import { SANDBOX_SESSION_TOKEN } from '@trymellon/js';

Utility exports

Helper functions exported from @trymellon/js:

ExportDescription
isTryMellonError(e)Type guard — returns true if e is a TryMellonError.
ConsoleLoggerDefault logger implementation. Pass a custom object matching the Logger interface to suppress or redirect SDK logs.
resolveCredentialName(aaguid)Resolves a human-readable authenticator name from an AAGUID (e.g. 'Touch ID', 'YubiKey 5').
getDeviceName()Returns a human-readable name for the current device/authenticator context.

@trymellon/js/platform · hosted onboarding

Sub-path for platforms that onboard their own maintainers onto TryMellon. Stateless — no publishable key. Full guide → Hosted onboarding.

import { createPlatform } from '@trymellon/js/platform';

const platform = createPlatform({ apiBaseUrl: 'https://api.trymellonauth.com' });

createPlatform(config?)

ArgTypeDescription
config.apiBaseUrlstring?Override the API base. Defaults to https://api.trymellon.com.

Returns TryMellonPlatform — 3 methods.

createSignupLink(options)

const link = await platform.createSignupLink({
  returnUrl: 'https://acme.com/onboarded',
  userRole: 'maintainer',
  refreshUrl: 'https://acme.com/signup-expired', // optional
  prefill: { companyName: 'ACME', email: 'f@acme.com' }, // UX only
});
// link.ok = true ⇒ link.value = { sessionId, hostedUrl, expiresInSeconds }

Client-side guards (fail-fast, zero HTTP): returnUrl must be https, refreshUrl (if present) must also be https.

getSignupStatus(sessionId)

Returns { status: 'pending_data' | 'pending_passkey' | 'completed' | 'expired' | 'failed', hostedUrl?, expiresInSeconds? }.

awaitSignupCompletion(sessionId, options?)

const controller = new AbortController();
const done = await platform.awaitSignupCompletion(sessionId, {
  signal: controller.signal,
  intervalMs: 2_000, // default
  maxAttempts: 60,   // default (~2 min)
});

Polls getSignupStatus until terminal. Rejects ABORT_ERROR on signal.abort(), TIMEOUT on exhaustion, SESSION_EXPIRED/SERVER_ERROR on terminal failure.

Type-level narrow: on the main TryMellon client, client.platform is typed never across every preset. Use the sub-path import — the TS compiler will reject client.platform.*.

Web Components

The SDK ships pre-built Web Components in @trymellon/js/ui. See Web Components for full documentation.

<script type="module">
  import '@trymellon/js/ui';
</script>
<trymellon-auth app-id="YOUR_APP_ID" publishable-key="cli_xxxx"></trymellon-auth>

Result type

All async methods that can fail return a Result<T, E>:

NameTypeDescription
result.okbooleantrue if success, false if error.
result.valueTThe success value when result.ok is true.
result.errorEThe error when result.ok is false.

Check result.ok before accessing result.value; use !result.ok and result.error for error handling.

TryMellonError

NameTypeDescription
codeTryMellonErrorCodeError code for programmatic handling.
messagestringHuman-readable error message.
detailsunknown?Additional error context.
isTryMellonErrortrueAlways true — use for type narrowing.

Error codes: NOT_SUPPORTED, USER_CANCELLED, PASSKEY_NOT_FOUND, SESSION_EXPIRED, NETWORK_FAILURE, INVALID_ARGUMENT, TIMEOUT, ABORT_ERROR, CHALLENGE_MISMATCH, RATE_LIMIT_EXCEEDED, TICKET_NOT_FOUND, TICKET_EXPIRED, TICKET_ALREADY_USED, PIN_MISMATCH, PIN_LOCKED, BRIDGE_SESSION_EXPIRED, OTP_INVALID_OR_EXPIRED, ACTION_CHALLENGE_EXPIRED, ACTION_ALREADY_CLAIMED, ACTION_PAYLOAD_MISMATCH, SECRET_ROTATION_FORBIDDEN, JWT_KID_MISMATCH, INTROSPECTION_FAILED, CUSTOM_CLAIM_NOT_ALLOWED, CUSTOM_CLAIMS_TOO_LARGE, FORBIDDEN, SERVER_ERROR, UNKNOWN_ERROR. See Events & Error handling.