Skip to content
View raw ↗

SDK Reference ​

foundation-sdk is the typed client your frontend uses to talk to its Foundation backend — auth, data, files, integrations, account, and config, from one instance you set up once.

The canonical, agent-oriented version of this reference is served at /agents/foundation-sdk-reference.md and bundled into llms-full.txt. This page is the same surface, rendered for reading.

Install ​

bash
npm install foundation-sdk
npm install aws-amplify            # Cognito apps
# or: npm install @auth0/auth0-spa-js   # Auth0 apps

Initialize ​

Await once, share everywhere. See Set up the SDK for dev vs production details.

ts
import { createFoundation } from 'foundation-sdk'
import { cognitoAuth } from 'foundation-sdk/cognito' // or auth0Auth from 'foundation-sdk/auth0'

const foundation = await createFoundation({
  configUrl: import.meta.env.VITE_FOUNDATION_CONFIG_URL,
  tenantId: import.meta.env.VITE_FOUNDATION_TENANT_ID,
  appId: import.meta.env.VITE_FOUNDATION_APP_ID,
  baseUrl: import.meta.env.VITE_FOUNDATION_API_BASE_URL, // dev-only
  auth: cognitoAuth,
})

In production, Foundation writes /foundation-env.json and the SDK reads it — so createFoundation({ auth }) works with no identity values.

Public init request ​

The SDK loads public bootstrap configuration by calling configUrl exactly as provided, usually https://.../api/v1/public/init. It separately loads authenticated backend configuration from the API base URL after auth. For tooling or non-JS clients that call the public endpoint directly, send these headers:

http
X-Foundation-Mvp-Tenant-Id: <tenant-id>
X-Foundation-Mvp-Application-Id: <application-id>

The values are the same tenantId and appId used during SDK initialization. Use these header names exactly; alternate tenant or application header names are not accepted.

A missing or blank required header returns 400 with a message naming the header(s) — Missing required header(s): X-Foundation-Mvp-Tenant-Id. An unknown or malformed application id returns 400 Unknown application.

Auth ​

ts
foundation.auth.user
foundation.auth.isAuthenticated
foundation.auth.getToken()
foundation.auth.login(options?)
foundation.auth.logout(options?)
foundation.auth.handleCallback(url?)
foundation.auth.signIn(email, password)
foundation.auth.signUp(email, password, metadata?)
foundation.auth.confirmSignUp(email, code)
foundation.auth.resendSignUpCode(email)
foundation.auth.forgotPassword(email)
foundation.auth.resetPassword(email, code, newPassword)
foundation.auth.onChange(callback)

Sign-in and sign-up return result objects — branch on result.isSignedIn / result.nextStep?.signInStep. Call handleCallback() on hosted-login callback routes, and refresh auth state after login, logout, callback, and registration. See Authentication.

signUp profile fields ​

signUp(email, password, metadata?) accepts an optional metadata object. Just pass the fields — the SDK routes each to the right place; you never construct Cognito attributes or client metadata yourself.

ts
await foundation.auth.signUp(email, password, {
  given_name: 'Ada',      // Cognito attribute
  family_name: 'Lovelace',// Cognito attribute
  name: 'Ada Lovelace',   // profile field -> saved on the account
  nickname: 'Ada',
  picture: 'https://…',
  locale: 'en-GB',
  timezone: 'Europe/London'
})
  • Profile fields — name, nickname, picture, locale, timezone — are stored on the Foundation account user record, not on the Cognito user. (The SDK forwards them via Cognito ClientMetadata; the backend persists them during registration.)
  • Cognito attributes — given_name, family_name, and any other pool-writable attribute — are written to Cognito.
  • Passing a profile field such as name as a raw Cognito attribute would fail with A client attempted to write unauthorized attribute; the SDK avoids this by routing it for you. Values are strings; null/undefined are dropped.

Database ​

ts
foundation.db.list<T>(entity, options?)
foundation.db.get<T>(entity, id)
foundation.db.create<T>(entity, data)
foundation.db.update<T>(entity, id, updates)
foundation.db.save<T>(entity, data)
foundation.db.delete(entity, id)

list options: { filters?, limit?, cursor?, orderBy?, orderDir? }. Paginate with cursor / nextCursor for lists that can grow. See Entities.

Files ​

ts
foundation.files.upload({ name, contentType, file, sha256 })
foundation.files.initiate({ name, contentType, contentLength, sha256, metadata? })
foundation.files.get(fileId)
foundation.files.delete(fileId)
foundation.files.list({ limit?, cursor? }?)

Compute sha256 before upload. Use initiate only for manual control of the signed upload. See Uploads & Files.

Integrations ​

ts
foundation.integration.all()
foundation.integration.list()
foundation.integration.connections()
foundation.integration.status(source)
foundation.integration.connect(source)
foundation.integration.disconnect(source, configurationId)

Use all() for catalog plus connection state. On connect(source), if the result has a url, open a popup or redirect, then refresh status. Only disconnect after explicit confirmation. See Integrations.

Account ​

ts
foundation.account.get<TUser, TAccount>()
foundation.account.update(data)
foundation.account.usage()
foundation.account.resendVerification()

usage() returns consumption vs configured limits — drives plan gating. See Billing.

Config ​

ts
foundation.config.app
foundation.config.features
foundation.config.plans
foundation.config.theme
foundation.config.connectors
foundation.config.resources
foundation.config.auth
foundation.config.raw

Read backend config to hide unavailable UI and apply theme- or plan-aware behavior instead of hard-coding. See Branding.

For apps acting as OAuth authorization servers:

ts
const client = await foundation.oauth.getClient(clientId)
const { code } = await foundation.oauth.authorizeConsent({
  client_id, redirect_uri, scope, state, code_challenge, code_challenge_method,
})

Only call authorizeConsent after explicit user approval, then redirect back with code and state.

Logging ​

ts
foundation.log.info(message, context?)
foundation.log.warn(message, context?)
foundation.log.error(message, context?)
foundation.log.event(eventName, data?)

Fire-and-forget — never block the UI on logging.

Web components ​

ts
import 'foundation-sdk/components'
;(window as any).__foundation = foundation
html
<foundation-connect integration-id="github-oauth"></foundation-connect>

Events: success, error, close. In Vue, configure isCustomElement for foundation-* tags. See Components & connector.

Critical rules ​

  • Always await createFoundation(...); initialize once and share it. The returned instance is fully initialized, so no separate foundation.ready wait is needed.
  • Use exactly one auth provider entry point.
  • baseUrl is dev-only — production must not depend on it.
  • Never put private secrets in frontend code.
  • Set window.__foundation only when using foundation-sdk/components.