Skip to content

How to Build and Document a High-Converting Link SDK for SaaS Integrations

A technical blueprint for building an embeddable Link SDK that ships SaaS integrations in days. Learn the architecture, UX, DX, and documentation trade-offs.

Uday Gajavalli Uday Gajavalli · · 15 min read
How to Build and Document a High-Converting Link SDK for SaaS Integrations

Your product manager just promised an enterprise prospect HubSpot, Salesforce, and BambooHR integrations by the end of the quarter. Your senior backend engineer estimates six weeks for the OAuth flow alone, another four weeks to build webhook signature verification across three different providers, and an unknown amount of time for the inevitable token-refresh fires that will trigger PagerDuty alerts at 3 AM. The deal closes in five weeks.

You are a startup CTO or engineering leader staring at a spreadsheet of lost deals, and the pattern is painfully obvious. Prospects run a successful evaluation, love your core product, and then ask the inevitable question: "Do you integrate with our HRIS and our CRM?" You reply that it is on the roadmap. By the time your engineering team ships it, the deal is completely cold.

The fastest way out of that math is to stop building a custom settings page for every integration and start shipping an embeddable Link SDK—a single drop-in component that handles OAuth, post-connection configuration, and the inevitable mess of native file pickers across every provider you support.

This guide provides a technical blueprint for designing an embeddable integration UI (often called a Link SDK) and writing the developer documentation that supports it. We will cover architectural trade-offs, UX conversion principles, rate limit handling, and edge cases like native file pickers.

A Link SDK is an embeddable JavaScript (or native mobile) component that renders the authentication UI for third-party integrations directly inside your product. Instead of building a bespoke Salesforce settings page, a HubSpot settings page, and a NetSuite settings page, you call a single link.open('salesforce') function. The SDK then handles OAuth redirects, token storage, error recovery, and post-connection configuration.

Why this matters in 2026:

  • 77% of buyers prioritize integration capabilities, and solutions that fail to integrate seamlessly with existing workflows are often deprioritized "regardless of features or price" (Demandbase, 2025). During assessment, buyers are primarily concerned with a software provider's ability to provide integration support (44%), making it the number one sales-related factor in driving a software decision, according to Gartner's 2024 Global Software Buying Trends report.
  • Buyers still mostly or fully define their purchase requirements 83% of the time before speaking with sales (6Sense, 2025). If your application lacks a polished, embedded way to connect third-party tools, prospects will assume your platform is an isolated silo.
  • Building OAuth for AI agents costs $200K+ over 3 years in engineering, maintenance, and delayed deals. The same math applies to customer-facing OAuth.

For the architectural difference between this and an internal automation, see What is a Customer-Facing Integration?.

The Business Case for an Embeddable Integration UI

Embeddable integration UI best practices start with acknowledging that your integrations page is a revenue driver, not just a technical settings panel.

Building a custom integration authentication UI from scratch is a massive capital expense. Organizations typically spend $30,000 to $500,000+ just for the initial build of their integration infrastructure, with annual maintenance running 15 to 25% of that original cost. That is merely the hard build number. The hidden cost is opportunity: every hour your senior engineers spend debugging a broken Salesforce custom field mapping or deciphering a cryptic OAuth error is an hour they are not building your core product.

The most expensive line item in a custom integration program is not the initial OAuth build. It is the long tail of provider-specific weirdness that compounds for years afterward.

Cost Bucket In-House Build Embeddable Link SDK
Initial OAuth build (per provider) 2 - 6 weeks < 1 day
Token refresh edge cases Permanent on-call surface Handled by vendor
Provider auth changes (Microsoft renaming AAD again) Emergency sprint Patch release
File picker UIs (Drive, SharePoint, Box) 4 - 8 weeks each Single function call
Annual maintenance per integration $50,000 - $150,000 Included

The Authsignal team puts it bluntly: "Authentication is a specialization. The teams who do it well have spent years on it, across hundreds of integrations, building up an understanding of failure modes that aren't obvious until they are. They've tracked regulatory changes across different jurisdictions. They've maintained libraries through breaking changes and security disclosures. That expertise accumulates slowly and it's genuinely hard to replicate quickly."

FusionAuth is more direct: "Fewer than 5% of engineering teams should build authentication from scratch. The complexity, security requirements, and ongoing maintenance typically outweigh the benefits unless you have very specific requirements and dedicated security expertise."

If you would not build your own SAML library, you should not build your own multi-provider OAuth UI either. An embeddable Link SDK solves this by moving the entire authentication lifecycle, token management, and UI rendering to a managed component.

Core UX Principles for High-Converting Authentication Flows

When a user clicks "Connect to Salesforce" inside your application, the subsequent flow determines whether they complete the integration or abandon the setup. A Link SDK lives in the moment a customer decides whether your product is real or vapor. Treat it like a checkout flow, not a settings panel.

The non-negotiables for Link SDK authentication UX:

  • One click to start: No "go to integrations, click new, select provider, paste API key." One button, one modal.
  • Eliminate the redirect loop of death: Never force the user to leave your application's context. Use popup windows or centered iframes for the OAuth grant screen, communicating back to the host window via the MessageChannel API or postMessage.
  • Maintain brand consistency: The SDK should accept CSS variables or configuration objects that match the host application's typography, button border radius, and primary colors. White-label API authentication builds trust. If it looks like a third-party widget, enterprise users will flag it in security review.
  • Handle popup blockers gracefully: Browsers block window.open calls that do not originate from a direct user interaction (like a click event). The SDK must initiate the popup synchronously within the click handler, then navigate the popup to the authorization URL once the backend generates the state parameters.
  • Inline error states: When Salesforce returns invalid_grant because the user is not an org admin, show a human-readable explanation, not a JSON dump.
  • Resumable flows: OAuth redirects break tabs, popup blockers, and mobile in-app browsers. The SDK must recover when a user comes back to a half-finished flow.
  • Pre-connection clarity: Tell users exactly which scopes you are requesting and why. "We need crm.objects.contacts.read to sync your contact list every 15 minutes" beats a Microsoft consent screen that lists 14 permissions.
  • Provide clear exit states: If a user cancels the flow, the SDK must return a predictable error state to the host application rather than leaving the UI hanging in a loading state.
Tip

Always pass a secure, unpredictable state parameter during the OAuth flow and verify it upon the callback. This prevents Cross-Site Request Forgery (CSRF) attacks against the integration setup process.

sequenceDiagram
    participant User
    participant HostApp as Host Application
    participant SDK as Link SDK
    participant Backend as Integration Platform
    participant Provider as Third-Party API

    User->>HostApp: Clicks "Connect"
    HostApp->>SDK: link.open()
    SDK->>Backend: Request Auth URL
    Backend-->>SDK: Return URL with state
    SDK->>SDK: Validate scopes, show consent screen
    SDK->>Provider: Open popup to Auth URL
    User->>Provider: Grants permission
    Provider->>Backend: Redirect with authorization code
    Backend->>Provider: Exchange code for tokens
    Provider-->>Backend: Access & Refresh Tokens
    Backend-->>SDK: PostMessage (Success)
    SDK-->>HostApp: onSuccess(integratedAccount)
    HostApp->>User: "Connected. Importing data..."

The most important conversion lever is what happens immediately after the success callback. A connected account that immediately shows imported data converts dramatically better than one that says "sync starting, check back in an hour."

Developer Experience (DX): Designing the SDK API Surface

SDKs act as a critical layer between host applications and the underlying system, where performance, security, and reliability matter most. If the implementing engineer at your customer's company has to read more than one page of docs to get a connect button rendering, you have already lost.

A utility class bundled with the SDK can take care of the Token Management life cycle and securely store all tokens. All the developer had to do was say, "Give me an AT (Access Token)," and have confidence in returning a valid AT without being concerned with what was happening under the hood. Apply the same philosophy to your Link SDK. Implementing engineers do not want to manage session state, poll for completion, or parse complex initialization objects.

Design rules for a high-converting API surface:

  1. One initialization function. Not a builder, not a factory, not a config DSL. They want a single function call.
  2. Promises over callbacks. Modern engineers expect await link.connect(...).
  3. TypeScript first. Ship types in the package. SDKs that are written in the targeted language can be more idiomatic when it comes to type safety. An SDK also makes it easier to predict how an API will respond to a request since the response object is typed.
  4. Predictable errors. Throw typed errors with stable error codes (USER_CANCELLED, POPUP_BLOCKED, INVALID_SCOPE, TOKEN_EXPIRED), not stringly-typed exceptions.
  5. Zero peer dependency drama. If your SDK forces React 18 or a specific bundler, you have made it un-installable for half your prospects.

A minimal surface that works looks like this:

import { TrutoLink } from '@truto/truto-link-sdk';
 
// Initialize the SDK with a single function
const link = new TrutoLink({
  token: 'YOUR_SHORT_LIVED_SESSION_TOKEN', // fetched from your backend
});
 
// Bind to a button click
document.getElementById('connect-btn').addEventListener('click', async () => {
  try {
    const result = await link.connect('salesforce');
    console.log('Successfully connected:', result.integrated_account_id);
    // Update host application UI and trigger syncs
  } catch (err) {
    if (err.code === 'USER_CANCELLED') return;
    console.error('Auth failed:', err.message);
    reportError(err);
  }
});

Behind this simple interface, the embedded integration platform is doing heavy lifting. The platform handles the entire OAuth lifecycle seamlessly behind the SDK, abstracting away provider-specific token management, refresh logic, and re-authentication flows. The host application never touches the actual third-party access token; it only receives an opaque identifier (integrated_account_id) that it uses to make proxy requests or receive webhooks.

Tip

The token used to initialize the SDK should be minted by your backend with a short TTL (a few minutes). Never put long-lived API keys in browser code. The SDK exchanges this token for an authenticated session against the integration platform.

Transparent Rate Limit Handling in SDKs

A common mistake in SDK design—and where most embedded integration platforms quietly screw their customers—is attempting to be "too helpful" by silently absorbing errors and automatically applying exponential backoff when hitting third-party rate limits.

This is an architectural anti-pattern. When an SDK silently retries a request for 45 seconds, it blocks the host application's execution thread, consumes connection pool resources, and masks underlying architectural bottlenecks. It ships an SDK that appears slow for reasons the implementing engineer cannot debug.

The correct behavior: pass the upstream error through, normalized into IETF standard headers, and let the caller decide how to handle it. Radical transparency always wins over black-box magic.

Truto ensures deterministic API behavior by passing HTTP 429 rate limit errors directly to the caller, following the IETF RateLimit Fields draft. Truto normalizes every provider's rate limit metadata into three headers:

  • ratelimit-limit: The maximum number of requests permitted in the current window.
  • ratelimit-remaining: The number of requests remaining in the current window.
  • ratelimit-reset: The time at which the current rate limit window resets (in UTC epoch seconds).

When Salesforce returns a 429 because you blew through the daily API quota, Truto returns the 429 directly to your caller. No retries, no silent backoff, no "this request took 47 seconds because we paused it."

try {
  const contacts = await truto.unified.crm.contacts.list({ ... });
} catch (err) {
  if (err.status === 429) {
    const resetSeconds = Number(err.headers['ratelimit-reset']);
    // Your retry strategy, not ours
    await scheduleRetry(resetSeconds);
  }
}

By exposing these headers, the SDK empowers the implementing engineer to handle retries using their own background workers, durable state, or scheduling primitives. The SDK abstracts authentication and schema differences; it does not abstract away the fact that Salesforce has a daily API call cap. For a deeper dive on multi-provider retry strategy, see Best Practices for Handling API Rate Limits and Retries.

Best Practices for Writing SDK Developer Documentation

Effective SDK documentation must prioritize immediate time-to-value for the implementing engineer. Good SDK docs are not a reference manual. They are a conversion funnel.

Quickstart guides and easy-to-follow code samples can help create a positive developer experience. A quick start guide serves as a brief, focused introduction to your SDK. It aims to take developers from zero to their first successful authentication call as swiftly as possible.

The structure that converts:

  1. The 60-Second Quickstart (above the fold): A zero-configuration code block demonstrating the absolute minimum required to render the UI and produce a working connect button in under five minutes. Include boilerplate code: Provide snippets of functional code that the developer can copy-paste to see immediate results.
  2. Authentication Prerequisites: Clear instructions on how to generate the short-lived session token required to initialize the SDK, and where the SDK's session boundary lives.
  3. Framework Recipes: React, Vue, vanilla JS, and Next.js App Router (because that is what 60% of new B2B SaaS frontends use).
  4. Configuration Reference & Recipes: A flat table detailing every configuration option. Include recipes like "how to pre-select an integration," "how to filter the integration catalog," and "how to white-label the modal."
  5. Error Handling & Codes: A comprehensive list of predictable error codes the SDK might throw, what triggers them, and what the user should do.
  6. Real-world Examples: Full end-to-end repos on GitHub, not just snippets.
  7. Changelog: APIs are not static; they evolve. Without a clear system for communicating these changes, you risk breaking your users' integrations and eroding their trust. Documenting API versions and maintaining a detailed changelog is a critical best practice that provides stability and transparency.

The most underrated section is a "things you don't have to worry about" page. Explicitly list what the SDK handles for the developer: token refresh, popup blocking, redirect URI mismatch, OAuth state CSRF, and mobile in-app browser quirks. Engineers comparing your SDK to a build-in-house plan will read this page very carefully.

Warning

Do not hide your error code reference behind a login wall. The first thing an engineer does when debugging at 2 AM is Google the error message. If your docs are gated, they will end up on Stack Overflow with an outdated answer.

Handling Edge Cases: Native File Pickers and Post-Connection Config

Basic OAuth flows are straightforward. A Link SDK that only handles OAuth is table stakes. The actual hard problems show up after the connection succeeds, testing how the UI handles vendor-specific requirements.

Native File Pickers for Cloud Storage

When connecting to Google Drive, OneDrive, SharePoint, Box, or Dropbox, enterprise users expect to see the native, vendor-provided file selection UI. They want Google's search bar, Microsoft's folder hierarchy, and Box's thumbnail previews. Rebuilding these UIs from scratch is a losing battle against vendor API changes.

Building a unified abstraction that launches the vendor-native UI (not a replica) requires understanding five different SDKs, popup vs inline rendering, OAuth-vs-app-key auth, MessageChannel protocols, and CORS allow-listing in five different developer consoles. We wrote about that mess in The Unholy Mess of File Picker APIs.

Truto's Link SDK exposes this as a single unified function (showFilePicker) that manages all script loading and cross-origin communication behind a consistent API:

import { showFilePicker } from '@truto/truto-link-sdk';
 
try {
  const pickedItems = await showFilePicker(
    'googledrive',           // or 'sharepoint', 'onedrive', 'box', 'dropbox'
    integratedAccountToken,
    {
      title: 'Select contract documents',
      maxItems: 5,
      trutoExpression: '$.($merge([{"selected_at": $now()}, $]))'
    }
  );
  console.log('Selected files:', pickedItems);
} catch (error) {
  console.error('Picker error:', error);
}

Internally, this single function routes to highly complex, provider-specific implementations:

  • Google Drive: The SDK dynamically loads multiple scripts (apis.google.com/js/api.js and accounts.google.com/gsi/client), fetches the Drive v3 REST discovery document, and constructs the picker using google.picker.PickerBuilder.
  • SharePoint and OneDrive: The SDK opens a blank popup window and submits a form via POST to Microsoft's FilePicker.aspx endpoint, establishing a MessageChannel protocol to listen for pick and close commands.
  • Box: The SDK injects Box UI Elements CSS and JavaScript from a CDN and renders an in-page, full-screen modal directly in the DOM.
  • Dropbox: The SDK utilizes the Dropbox Chooser, polling the browser for window.Dropbox readiness and authenticating via an app key rather than an OAuth token.

Data Transformation at the Edge

Once a user selects files, the resulting data structures vary wildly between providers. To normalize this, advanced Link SDKs allow developers to manipulate the returned data before it hits the host application.

Truto allows post-selection JSONata transformations (trutoExpression) directly within the SDK configuration. You can add timestamps, filter by MIME type, reshape fields, or merge with existing selections before they are persisted. This is the kind of post-selection transform that takes most teams a full sprint to build per provider.

Dynamic Post-Connection Configuration

The second hard problem: many integrations require configuration immediately after the OAuth flow completes. After connecting a CRM, the user must select which pipeline to sync, which custom field maps to your lead_score concept, or which Slack channel should receive notifications.

This UI needs to render dynamically based on data fetched from the freshly connected account. A resilient Link UI supports dynamic post-connection configuration. Instead of forcing the host application to build custom dropdowns for every integration, the SDK should read a JSON schema from the integration platform and dynamically render the necessary form fields, validating the user's input before marking the connection as fully active. For more on designing these interfaces, see our guide on post-connection configuration UI patterns.

flowchart LR
    A[OAuth Success] --> B[Fetch Account Metadata]
    B --> C[Render Config Form<br>from JSON Schema]
    C --> D[User Selects Pipelines<br>Fields Channels]
    D --> E[PATCH integrated_account<br>context]
    E --> F[Backend Starts Sync]

Your backend syncs are now parameterized by user choices without you writing a single line of HubSpot-pipeline-picker code.

Your engineering team's time is your most constrained resource. Spending sprints building bespoke OAuth popups, deciphering Microsoft's file picker documentation, and writing retry logic for undocumented rate limits is a strategic error. However, radical honesty dictates that an embedded Link SDK is not a magic bullet.

Three things to plan for when moving away from in-house builds:

  1. OAuth app ownership: If you use a vendor's shared OAuth app, switching providers later means re-authenticating every customer. Pick a Link SDK that lets you bring your own OAuth credentials per provider. We wrote about the trap in OAuth App Ownership.
  2. UI customization ceiling: Even the most flexible SDK constrains your design system. If your CEO wants the connect flow to feel "completely native," budget a week to theme it properly and accept that some provider screens (like Google's consent screen or Microsoft's File Picker) are owned by the provider and cannot be restyled.
  3. Security review surface: Enterprise prospects will ask where the tokens live, who can decrypt them, and what your data residency story is. Pick a vendor with SOC 2 Type II, configurable data regions, and a clean answer to "do you store our customers' API responses by default?"

For the full build-vs-buy math, see Build vs Buy: The True Cost of Building SaaS Integrations In-House.

If you are scoping this work right now, here is the order of operations that minimizes risk:

  1. Map your top 5 integrations by deal-blocking frequency. Not by what your engineers find interesting—by what sales loses deals over.
  2. Decide the auth model. Bring-your-own OAuth credentials (recommended for enterprise) or shared (faster to ship, painful to migrate).
  3. Spike the Link SDK against one integration end-to-end. Test OAuth, post-connection config, and one data sync. Time-box this to a week.
  4. Write the docs before you write the marketing page. If your quickstart cannot get an engineer to a working connect button in 5 minutes, fix the SDK, not the copy.
  5. Instrument the funnel. Track connect-button-clicked, OAuth-redirect-completed, post-config-saved, and first-sync-succeeded. The drop-off between steps tells you exactly where the SDK fails customers.

By adopting an embeddable Link SDK, you offload the authentication lifecycle, UI edge cases, and token management to dedicated infrastructure. You give your implementing engineers a clean API surface with predictable error handling. Most importantly, you give your sales team the ability to say "yes" to enterprise integration requests without derailing your core product roadmap.

A Link SDK is the highest-leverage component in your integration stack. Spend a sprint on it, not a quarter. And if you would rather not own the file picker matrix, the OAuth refresh edge cases, or the next time Microsoft renames its identity platform, that is exactly what a managed unified API platform is for.

FAQ

What is a Link SDK in a SaaS integration platform?
A Link SDK is an embeddable JavaScript or native mobile component that renders the authentication UI for third-party integrations directly inside your product. It handles OAuth redirects, token storage, error recovery, and post-connection configuration through a single function call.
How much does it cost to build custom integration infrastructure?
Organizations typically spend $30,000 to $500,000+ just for the initial build of custom integration infrastructure, with annual maintenance running $50,000 to $150,000 once you factor in token refresh edge cases, provider auth changes, and file picker UIs.
How should SDKs handle third-party API rate limits?
SDKs should not silently absorb errors with automatic retries. They should pass HTTP 429 errors directly to the caller alongside standardized IETF rate limit headers (ratelimit-limit, ratelimit-remaining, ratelimit-reset) to allow the host application to manage its own backoff logic.
How do you handle native file pickers like Google Drive and SharePoint in a unified SDK?
A well-designed Link SDK exposes a single function that internally routes to the vendor-native picker UI for each provider. The SDK handles script loading, OAuth token injection, popup vs inline rendering, and post-selection persistence, so engineers do not have to learn multiple vendor SDKs.
What should SDK developer documentation include to maximize conversion?
Start with a quickstart that produces a working integration in under five minutes using copy-pasteable boilerplate. Add authentication prerequisites, framework-specific recipes, a complete error code reference, real-world example repos, and a published changelog. Never gate the error reference behind a login wall.

More from our Blog