For AI agents: a documentation index is available at the root level at /llms.txt and /llms-full.txt. Append /llms.txt to any URL for a page-level index, or .md for the markdown version of any page.
GitHubGet Support
DocsGuidesAPI Reference
DocsGuidesAPI Reference
  • Get started
    • Overview
    • Partner Setup
    • Quickstart
  • Guides
    • Authentication
    • Profile Sync
    • Artifacts
    • Key Concepts
  • Changelog
    • Changelog
LogoLogo
GitHubGet Support
On this page
  • How it works
  • Configuration
  • Static data
  • Async provider
  • Data types
  • User profile
  • Address
  • Insurance
  • Dependents
  • Linking dependents to insurance plans
  • Full example
  • Behavior notes
  • Next steps
Guides

Profile Sync

Pre-populate user data during authentication

||View as Markdown|
Was this page helpful?
Previous

Authentication

Next

Artifacts

Built with

When a user authenticates, the SDK can send partner-collected data — profile details, address, insurance, and dependents — alongside the auth.upgrade message. Sunny uses this to pre-populate the user’s account, removing the need for the user to re-enter information they’ve already provided to your application.

How it works

Profile sync data is included in the auth.upgrade WebSocket message that fires when a user authenticates. The backend uses upsert semantics: it only creates or updates records for the fields you provide, and leaves everything else untouched.

Configuration

Pass authUpgradeProfileSync to createSunnyChat. You can provide static data or an async function that resolves the data at authentication time.

Static data

1import { createSunnyChat } from "@sunnyhealthai/agents-sdk";
2
3const chat = createSunnyChat({
4 container: document.getElementById("chat"),
5 partnerIdentifier: "acme-health",
6 publicKey: "pk-sunnyagents_abc_xyz",
7 authType: "tokenExchange",
8 idTokenProvider: async () => getMyToken(),
9 authUpgradeProfileSync: {
10 user_profile: {
11 first_name: "Jane",
12 last_name: "Doe",
13 phone: "+15551234567",
14 date_of_birth: "1990-03-15",
15 gender: "female",
16 },
17 user_address: {
18 address_line_1: "123 Main St",
19 city: "San Francisco",
20 state: "CA",
21 zip_code: "94102",
22 },
23 },
24});

Async provider

Use a function when the data needs to be fetched at authentication time — for example, from your own API:

1const chat = createSunnyChat({
2 container: document.getElementById("chat"),
3 partnerIdentifier: "acme-health",
4 publicKey: "pk-sunnyagents_abc_xyz",
5 authType: "tokenExchange",
6 idTokenProvider: async () => getMyToken(),
7 authUpgradeProfileSync: async () => {
8 const res = await fetch("/api/user/profile", { credentials: "include" });
9 if (!res.ok) return null;
10 const user = await res.json();
11 return {
12 user_profile: {
13 first_name: user.firstName,
14 last_name: user.lastName,
15 phone: user.phone,
16 date_of_birth: user.dob,
17 },
18 user_address: user.address
19 ? {
20 address_line_1: user.address.line1,
21 city: user.address.city,
22 state: user.address.state,
23 zip_code: user.address.zip,
24 }
25 : undefined,
26 insurances: user.insurance
27 ? [
28 {
29 partner_plan_id: user.insurance.planId,
30 member_id: user.insurance.memberId,
31 group_id: user.insurance.groupId,
32 },
33 ]
34 : undefined,
35 };
36 },
37});

Returning null from the provider skips profile sync entirely — the user authenticates normally without any pre-populated data.

Data types

All fields in authUpgradeProfileSync are optional. Include only what your application has collected.

User profile

Basic demographic information. All fields are optional; only provided fields are updated.

1interface AuthUpgradeProfile {
2 first_name?: string | null;
3 last_name?: string | null;
4 phone?: string | null;
5 date_of_birth?: string | null; // "YYYY-MM-DD"
6 gender?: string | null; // "male", "female", "other"
7}

Address

Mailing address for the user. When provided, address_line_1, city, state, and zip_code are required.

1interface AuthUpgradeAddress {
2 address_line_1: string;
3 address_line_2?: string | null;
4 city: string;
5 state: string;
6 zip_code: string;
7 country?: string; // defaults to "USA"
8}

Insurance

Insurance plan records. Reference the plan with exactly one of partner_plan_id (the plan’s UUID from Sunny Central) or plan_alias (a developer-defined alias configured for your partner). Aliases let you use a stable, human-readable identifier instead of managing raw UUIDs, and are resolved at runtime, scoped to your partner. Either way, this requires partnerIdentifier on the SDK connection.

1interface AuthUpgradeInsurance {
2 partner_plan_id?: string; // UUID from Sunny Central -- provide this OR plan_alias
3 plan_alias?: string; // developer-defined alias -- provide this OR partner_plan_id
4 member_id: string;
5 group_id: string;
6}

Referencing a plan by alias:

1authUpgradeProfileSync: {
2 insurances: [
3 { plan_alias: "gold-ppo-2024", member_id: "M001", group_id: "G100" },
4 ],
5}

Add and manage aliases from the Developer Tools → Plans & Aliases section of the Sunny Central dashboard. Plans themselves are configured by Sunny — contact your integration owner to add or change a plan.

Dependents

Family members or dependents covered under the user’s insurance. Each dependent can be linked to a specific insurance plan by index.

1interface AuthUpgradeDependent {
2 first_name: string;
3 last_name: string;
4 date_of_birth: string; // "YYYY-MM-DD"
5 gender?: string | null;
6 relationship_code: string; // Stedi code (see table below)
7 member_id?: string | null; // if different from subscriber
8 insurance_index?: number | null; // index into the insurances array
9}
Relationship codes

The relationship_code field uses Stedi relationship codes:

CodeRelationship
18Self
01Spouse
19Child
20Employee
21Unknown
39Organ donor
40Cadaver donor
53Life partner
G8Other relationship

Linking dependents to insurance plans

The insurance_index field links a dependent to a specific entry in the insurances array (zero-based). If omitted, the dependent is associated with the first insurance plan.

1authUpgradeProfileSync: {
2 insurances: [
3 { partner_plan_id: "plan-a-uuid", member_id: "M001", group_id: "G100" },
4 { partner_plan_id: "plan-b-uuid", member_id: "M002", group_id: "G200" },
5 ],
6 dependents: [
7 {
8 first_name: "Alex",
9 last_name: "Doe",
10 date_of_birth: "2015-06-01",
11 relationship_code: "19", // child
12 insurance_index: 0, // covered under plan-a
13 },
14 {
15 first_name: "Sam",
16 last_name: "Doe",
17 date_of_birth: "1991-11-20",
18 relationship_code: "01", // spouse
19 // insurance_index omitted -- defaults to first plan (plan-a)
20 },
21 ],
22}

Full example

A complete example syncing all data types with an async provider:

1import { createSunnyChat } from "@sunnyhealthai/agents-sdk";
2
3const chat = createSunnyChat({
4 container: document.getElementById("chat"),
5 partnerIdentifier: "acme-health",
6 publicKey: "pk-sunnyagents_abc_xyz",
7 authType: "tokenExchange",
8 idTokenProvider: async () => getMyToken(),
9 authUpgradeProfileSync: async () => {
10 const user = await fetchCurrentUser();
11 return {
12 user_profile: {
13 first_name: user.firstName,
14 last_name: user.lastName,
15 phone: user.phone,
16 date_of_birth: user.dob,
17 gender: user.gender,
18 },
19 user_address: {
20 address_line_1: user.address.street,
21 city: user.address.city,
22 state: user.address.state,
23 zip_code: user.address.zip,
24 },
25 insurances: user.plans.map((plan) => ({
26 partner_plan_id: plan.sunnyPlanId,
27 member_id: plan.memberId,
28 group_id: plan.groupId,
29 })),
30 dependents: user.dependents.map((dep, i) => ({
31 first_name: dep.firstName,
32 last_name: dep.lastName,
33 date_of_birth: dep.dob,
34 gender: dep.gender,
35 relationship_code: dep.relationshipCode,
36 member_id: dep.memberId,
37 insurance_index: dep.planIndex,
38 })),
39 };
40 },
41});

Behavior notes

  • Upsert semantics — the backend creates new records or updates existing ones. Existing data not covered by the payload is left unchanged.
  • Dependent deduplication — dependents are matched by natural key (first name + last name + date of birth). Sending the same dependent twice updates the existing record rather than creating a duplicate.
  • Auth mode compatibility — profile sync works with all authentication modes (token exchange and passwordless).
  • Timing — the async provider is called at authentication time, just before the auth.upgrade message is sent. This ensures data is as fresh as possible.

Next steps

  • Authentication — Configure authentication modes
  • Key Concepts — Conversations, events, and state management
  • API Reference — REST and WebSocket API schemas