Partner Connect SDK
Promise-based JavaScript SDK for secure cross-origin communication between partner apps and LearnCard
Last verified against @learncard/partner-connect v0.2.16. When in doubt, the runtime types in packages/learn-card-partner-connect-sdk/src/types.ts and the Zod validators in @learncard/types (packages/learn-card-types/src/lcn.ts) are the source of truth.
The Partner Connect SDK transforms complex postMessage communication into clean, modern Promise-based functions. It handles the entire cross-origin message lifecycle, including request queuing, origin validation, and timeout management.
Features
🔒 Secure: Multi-layered origin validation prevents unauthorized access
🎯 Type-safe: Full TypeScript support with comprehensive type definitions
⚡ Promise-based: Modern async/await API eliminates callback complexity
🧹 Clean: Abstracts away all postMessage implementation details
📦 Lightweight: Zero runtime dependencies, ~8KB minified
🛡️ Robust: Built-in timeout handling and structured error management
Installation
npm install @learncard/partner-connectpnpm add @learncard/partner-connectyarn add @learncard/partner-connectQuick Start
import { createPartnerConnect } from '@learncard/partner-connect';
// Initialize the SDK
const learnCard = createPartnerConnect({
hostOrigin: 'https://learncard.app',
});
// Request user identity (SSO)
try {
const identity = await learnCard.requestIdentity();
console.log('User DID:', identity.user.did);
console.log('JWT Token:', identity.token);
} catch (error) {
if (error.code === 'LC_UNAUTHENTICATED') {
console.log('User is not logged in');
}
}API Reference
Factory Function
createPartnerConnect(options?)
createPartnerConnect(options?)Creates a new Partner Connect SDK instance.
Parameters:
options(PartnerConnectOptions, optional): Configuration options. Defaults to{ hostOrigin: 'https://learncard.app' }.
Returns: PartnerConnect instance
Example:
You can also import and instantiate the PartnerConnect class directly:
Configuration
PartnerConnectOptions
PartnerConnectOptionsCore Methods
requestIdentity()
requestIdentity()Request user identity from LearnCard for Single Sign-On authentication.
Returns: Promise<IdentityResponse>
Example:
Response Type:
sendCredential(input)
sendCredential(input)Send a credential to the user's LearnCard wallet. Supports two modes:
Mode 1: Template-Based Issuance (Recommended for App Store Apps)
Issue a credential using a pre-configured boost template attached to your App Store listing. LearnCard handles signing and delivery.
Parameters:
input(TemplateCredentialInput): Template alias and optional data
Returns: Promise<TemplateCredentialResponse>
Mode 2: Raw Credential
Send a pre-signed verifiable credential directly. Your backend must issue and sign the credential first.
Parameters:
input(unknown): A signed verifiable credential object
Returns: Promise<SendCredentialResponse>
For App Store embedded apps, template-based issuance is strongly recommended. See Connect an Embedded App for a complete walkthrough.
launchFeature(featurePath, initialPrompt?)
launchFeature(featurePath, initialPrompt?)Navigate the LearnCard host wallet to one of its built-in features. Use this when you want to send the user from your embedded app into a wallet route (e.g. AI Topics, Wallet Share, Profile).
Don't confuse this with sendNotification({ actionPath }). launchFeature paths resolve inside the LearnCard wallet. actionPath paths resolve inside your embedded app's iframe. See the comparison table below.
Parameters:
featurePath(string): Wallet route to navigate to (e.g.,/ai/topics,/wallet/share,/profile)initialPrompt(string, optional): Initial prompt or data to pass to the feature
Returns: Promise<void>
Errors: LC_TIMEOUT, UNAUTHORIZED (if your app lacks the launch_feature permission)
Example:
launchFeature vs sendNotification actionPath
launchFeature vs sendNotification actionPathThese two APIs both take a /path string and look interchangeable, but they navigate to different origins:
launchFeature(path)
LearnCard wallet
You want to send the user into a wallet feature (/ai/topics, /wallet/share, /profile). Path is interpreted by the LearnCard host.
sendNotification({ actionPath })
Your embedded app
You want a notification's tap action to deep-link the user to a route inside your own app's iframe. Path is appended to your app's URL.
Bridge pattern — deep-linking from a notification to a wallet feature:
If you want a notification to take the user to a wallet route (e.g. /ai/topics), you must route them through one of your own pages that calls launchFeature():
The wallet's iframe host enforces this: any actionPath is appended to your app's iframe URL and the host explicitly rejects values that would escape your origin.
askCredentialSearch(verifiablePresentationRequest)
askCredentialSearch(verifiablePresentationRequest)Request credentials from the user's wallet using query criteria.
Parameters:
verifiablePresentationRequest(VerifiablePresentationRequest): Query specification
Returns: Promise<CredentialSearchResponse>
Example:
askCredentialSpecific(credentialId)
askCredentialSpecific(credentialId)Request a specific credential by ID.
Parameters:
credentialId(string): The ID of the credential to request
Returns: Promise<CredentialSpecificResponse>
Example:
requestConsent(contractUri?, options?)
requestConsent(contractUri?, options?)Request user consent for data access permissions.
App Store Apps: If your app is installed from the LearnCard App Store and has a consent contract configured in its integration settings, you can omit the contractUri parameter. The SDK will automatically resolve the configured contract from your listing.
Parameters:
contractUri(string, optional): URI of the consent contract. Can be omitted for App Store apps with configured contracts.options(RequestConsentOptions, optional): Additional options for the consent flow
redirect
boolean
false
If true, redirects to the contract's configured URL after consent granted
Returns: Promise<ConsentResponse>
Examples:
initiateTemplateIssue(templateId, draftRecipients?)
initiateTemplateIssue(templateId, draftRecipients?)Initiate a template-based credential issuance flow.
Parameters:
templateId(string): ID of the template/boost to issuedraftRecipients(string[], optional): Array of recipient DIDs
Returns: Promise<TemplateIssueResponse>
Example:
requestLearnerContext(options?)
requestLearnerContext(options?)Request comprehensive learner context for AI tutoring and personalization systems.
This method retrieves the user's credentials and personal data (with their consent), then formats them into either an LLM-ready prompt or structured data that can be used to personalize AI experiences.
Use Cases:
AI tutors that adapt to learner's existing skills and credentials
Personalized learning pathway recommendations
Smart content that adjusts based on learner history
Intelligent assessment systems
Parameters:
options(RequestLearnerContextOptions, optional): Configuration for what data to include and how to format it
includeCredentials
boolean
true
Whether to include user's credentials in the context
includePersonalData
boolean
false
Whether to include personal data (name, bio, etc.)
format
'prompt' | 'structured'
'prompt'
Format of the response
instructions
string
-
Optional instructions to guide LLM prompt generation
detailLevel
'compact' | 'expanded'
'compact'
Level of detail in generated content
Returns: Promise<LearnerContextResponse>
Example - AI Tutor Integration:
Example - Structured Data Access:
Error Handling:
Prerequisites for Learner Context:
Your app must be installed from the LearnCard App Store
The user must have consented to a contract that grants access to their credentials
The consent contract must be configured in your app's listing integration
Use requestConsent() before calling requestLearnerContext() if the user hasn't consented yet.
sendAiSessionCredential(input)
sendAiSessionCredential(input)Send an AI Session credential to record a learning interaction. AI Sessions are organized under AI Topics, creating a structured history of AI tutoring sessions that appears in the user's AI Topics page.
Use Cases:
AI Tutoring Apps - Record what was learned during a tutoring session
Learning Assistants - Track learning progress and outcomes
Skill Assessment - Document demonstrated competencies
Learning Pathways - Build a history of learning interactions
Parameters:
input(SendAiSessionCredentialInput): Session details
sessionTitle
string
Yes
Title of this specific AI session
summaryData
SummaryCredentialData
Yes
Structured data about what was learned
metadata
Record<string, unknown>
No
Optional metadata for the session
Summary Data Structure:
Schema verified against SDK v0.2.16. The fields are title, summary, learned, skills, nextSteps, reflections — not keyTakeaways/skillsDemonstrated/learningOutcomes. Earlier versions of these docs showed an incorrect schema; if you're upgrading, double-check your call sites.
Returns: Promise<SendAiSessionCredentialResponse>
Example - Recording a Learning Session:
How It Works:
Topic Creation/Reuse: The first session from your app creates an AI Topic. Subsequent sessions reuse this topic.
Session Credential: Each call creates a new AI Session credential under the topic.
Automatic Storage: Credentials are immediately stored in the user's LearnCloud wallet.
AI Topics Page: Sessions appear in the user's AI Topics section for review.
Session Hierarchy:
Prerequisites for AI Sessions:
Your app must be installed from the LearnCard App Store
The user must have consented to share their learning data
Call
requestConsent()before sending AI sessions if not already consented
The AI Topic is automatically created on the first session and reused for all subsequent sessions from your app.
Errors: LC_UNAUTHENTICATED, UNAUTHORIZED, USER_REJECTED, LC_TIMEOUT, BAD_REQUEST (when summaryData fails server-side validation — see the Source-of-Truth note below).
Schema Source of Truth
The summaryData shape is defined by SummaryCredentialDataValidator in @learncard/types (packages/learn-card-types/src/lcn.ts). The brain service deep-validates every sendAiSessionCredential call against this discriminated union, so a malformed summaryData will fail fast with a clear zod error rather than producing a broken credential.
sendNotification(input)
sendNotification(input)Send a notification to the current user from this app. The notification appears in the user's LearnCard notification inbox.
Parameters: AppNotificationInput
title
string
No
Notification title.
body
string
No
Notification body text.
actionPath
string
No
App-local path. When the user taps the notification, this path is appended to your app's iframe URL. See below.
category
string
No
Optional category tag for grouping notifications.
priority
'normal' | 'high'
No
Visual priority. 'high' notifications are styled more prominently in the inbox.
Returns: Promise<AppNotificationResponse>
Errors: LC_UNAUTHENTICATED, UNAUTHORIZED, LC_TIMEOUT
actionPath is APP-LOCAL. It is appended to your embedded app's iframe URL — not routed inside the LearnCard wallet. If you want to deep-link into a wallet route (e.g. /ai/topics), use the bridge pattern shown above.
Example — notify within your own app:
Example — bridge to a wallet feature:
Counters: incrementCounter, getCounter, getCounters
incrementCounter, getCounter, getCountersLightweight per-user-app counters for tracking app-defined integer state (e.g. "sessions completed", "streak days"). Counters are scoped to (user, listing) — every user has an independent set of counters per app.
Limits (load-bearing — design around these):
Maximum 50 distinct keys per
(user, app)pairMaximum 100 writes per minute per
(user, app)pairInteger values only (use
Math.flooror pre-aggregate if you need fractional state)Key format:
^[a-zA-Z0-9_-]+$, 1–64 characters
If you need to track more than 50 things, consolidate (e.g. one lessons_completed counter rather than one counter per lesson).
Signatures:
Examples:
Errors: LC_UNAUTHENTICATED, UNAUTHORIZED, BAD_REQUEST (invalid key format, > 50 keys, or rate-limit exceeded), LC_TIMEOUT
destroy()
destroy()Clean up the SDK and remove event listeners.
Returns: void
Example:
Security Model
The Partner Connect SDK implements comprehensive security measures:
Origin Validation
Strict Enforcement:
Incoming messages must exactly match the configured host origin
No wildcard (
*) origins are ever usedQuery parameter overrides are validated against whitelist
Configuration Hierarchy:
Default:
https://learncard.app(security anchor)Query Parameter Override:
?lc_host_override=https://staging.learncard.appConfigured Origin: From
hostOriginoption
Example:
Message Security
Protocol Verification: Messages must match expected protocol version
Request ID Tracking: Only tracked requests are processed
Timeout Protection: Requests automatically timeout to prevent hanging
Cleanup on Destroy: Pending requests are properly rejected
Error Handling
All SDK methods reject with a PartnerConnectError (a real Error subclass) carrying both code and message. The legacy LearnCardError shape is preserved — error.code keeps working — so existing call sites continue to function unchanged:
The LearnCardError interface remains exported for backwards compatibility:
Error Codes
LC_TIMEOUT
Request timed out
LC_UNAUTHENTICATED
User not logged in
USER_REJECTED
User declined the request
CREDENTIAL_NOT_FOUND
Requested credential doesn't exist
UNAUTHORIZED
User lacks permission
TEMPLATE_NOT_FOUND
Template doesn't exist
SDK_NOT_INITIALIZED
SDK not properly initialized
SDK_DESTROYED
SDK was destroyed before completion
Error Handling Patterns
Advanced Configuration
Multiple Origins (Staging Support)
Native App Support
For Capacitor/Ionic apps:
Custom Timeouts
Browser Support
Chrome/Edge: 90+
Firefox: 88+
Safari: 14+
Mobile: iOS Safari 14+, Android Chrome 90+
Required APIs:
postMessagePromiseURLSearchParamsaddEventListener
Migration Guide
From Manual postMessage
Before (80+ lines of boilerplate):
After (3 lines):
Benefits:
85% code reduction in typical integrations
Type safety with full TypeScript support
Better error handling with structured error codes
Security improvements with origin validation
No manual cleanup required
Examples
SSO Authentication Flow
Credential Gating (Premium Content)
Credential Issuance (Certificate Award)
TypeScript Types
All types are exported from the package for full type safety:
Key Type Definitions
Related Documentation
Connect an Embedded App - Step-by-step guide for App Store credential issuance
LearnCard Core SDK - Backend credential operations
LearnCard Network - Network integration
Creating Connected Websites - Integration guide
App Store Development - LearnCard app ecosystem
Last updated
Was this helpful?