Integration Guide

Tax Documentation React SDK

Use Taxbit's React SDK to collect W-9, W-8, DPS, and Self-Cert documentation directly within your application.

Package: @taxbit/react-sdk on npm

QuestionnaireRegulationsYour end user is…
W-FORMIRS Forms 1099, backup withholding, US FDAP treaty claimsA US person (W-9) or foreign person (W-8)
DPSDAC7 (EU), MRDP, UK, NZ, CanadaA seller on your digital platform
SELF-CERTCRS, CARF, DAC8A financial account holder or crypto-asset user

For regulatory background on each questionnaire type, see Tax documentation overview.

How it works

Integrating the SDK involves server-side setup (obtaining tokens and creating Account Owners via the Taxbit API) and client-side rendering (embedding the TaxbitQuestionnaire component in your React app).

sequenceDiagram
    participant Server as Your Server
    participant Taxbit as Taxbit API
    participant Client as Your React App

    Server->>Taxbit: POST /v1/oauth/token
    Taxbit-->>Server: tenant-scoped bearer token (24h)

    Server->>Taxbit: POST /v1/account-owners
    Taxbit-->>Server: 201 Created

    Server->>Taxbit: POST /v1/oauth/account-owner-token
    Taxbit-->>Server: Account Owner-scoped bearer token (24h)

    Server->>Client: Pass Account Owner-scoped token

    Client->>Taxbit: <TaxbitQuestionnaire /> submits form
    Taxbit-->>Client: Success

A · Get the SDK running

Frontend setup. See a working form in under 5 minutes.

01 · Gather your credentials Required

Log in to the Taxbit Dashboard and navigate to Settings > Developer Settings to find your environment-specific credentials.

CredentialPurpose
client_idPublic identifier for your integration
client_secretServer-side only. Never expose to the browser
tenant_idIdentifies your organization in Taxbit
🚧

Keep your client_secret secure

Store it in a secrets manager or environment variable. Anyone with the secret can impersonate your tenant.

02 · Install the SDK Required

The SDK is published as @taxbit/react-sdk. See the npm page for the latest version.

npm install @taxbit/react-sdk

Compatibility: React 16, 17, 18, 19 · TypeScript 4, 5

03 · Update your Content Security Policy If applicable

If your app uses a Content Security Policy, add the following directive to allow the SDK to reach the Taxbit API:

connect-src https://*.taxbit.com;

Without this, the SDK will render but API calls will silently fail. Check this before testing in production.

04 · Try it in demo mode Recommended

Before dealing with authentication, render the SDK in demo mode. No server, no token, no API calls.

import '@taxbit/react-sdk/style/inline.css';
import { TaxbitQuestionnaire } from '@taxbit/react-sdk';

export function DemoTaxForm() {
  return (
    <TaxbitQuestionnaire
      questionnaire="W-FORM"
      demoMode
    />
  );
}

Demo mode works with all three questionnaire types. The form renders and accepts input, but no data is sent to a server.

If the form doesn't render, check your browser console for errors. Common issues include missing CSS imports and React version conflicts.

Testing TIN validation in demo mode: TINs containing 0 return valid, 6 return invalid, all others return pending. See Component and hook reference for details.

05 · Render the questionnaire component Required

Once you have a bearer token from your backend (see Phase B), swap demoMode for a real bearerToken.

import '@taxbit/react-sdk/style/inline.css';
import { TaxbitQuestionnaire } from '@taxbit/react-sdk';

export function TaxFormStep({ bearerToken }) {
  return (
    <TaxbitQuestionnaire
      bearerToken={bearerToken}
      questionnaire="W-FORM"     // "DPS" | "SELF-CERT" | "W-FORM"
      language="en-us"
      onSuccess={(data) => console.log('submitted', data)}
    />
  );
}

Where to embed

Consider embedding the SDK at the end of your onboarding process or in the Account Profile / Settings section so tax documentation collection feels like a natural part of account creation.

🚧

Mobile apps

The SDK is a web-based solution. For native mobile apps, open an in-app webview that loads the SDK.

📘

Adaptive Mode for returning users

Set adaptiveMode="skipLock" to lock pre-filled fields as read-only, or "skipEdit" to let users update them. This turns a multi-screen form into a 2-click confirmation. See Adaptive mode.

See Component and hook reference for the full props table.


B · Connecting the backend

Server-side setup. Tokens, Account Owners, and the security boundary.

Key API endpoints

MethodEndpointPurpose
POST/v1/oauth/tokenTenant-scoped bearer token
POST/v1/account-ownersCreate an Account Owner
POST/v1/oauth/account-owner-tokenAccount Owner-scoped bearer token for the SDK

Base URL: https://api.multi1.enterprise.taxbit.com. This is the same for both sandbox and production environments. Your credentials determine which environment you are working in.

06 · Request a tenant-scoped bearer token Required

The tenant-scoped token lets your server create Account Owners. Valid for 24 hours.

MethodEndpoint
POST/v1/oauth/token
// Server-side — Node.js
const response = await fetch(
  "https://api.multi1.enterprise.taxbit.com/v1/oauth/token",
  {
    method: "POST",
    headers: { "Content-Type": "application/x-www-form-urlencoded" },
    body: new URLSearchParams({
      grant_type: "client_credentials",
      client_id:     process.env.TAXBIT_CLIENT_ID,
      client_secret: process.env.TAXBIT_CLIENT_SECRET,
      tenant_id:     process.env.TAXBIT_TENANT_ID,
    }),
  }
);

const { access_token: tenantToken } = await response.json();
📘

Server-side only

This request must be made from your backend. Browser-based requests will be declined to keep your client_secret confidential.

Cache this token

Cache the 24-hour tenant token server-side. Only fetch Account Owner-scoped tokens when initializing the SDK, not on every login or page transition.

07 · Create an Account Owner Required

Only id and account_owner_type are required.

MethodEndpoint
POST/v1/account-owners
// Server-side — Node.js
const aoResponse = await fetch(
  "https://api.multi1.enterprise.taxbit.com/v1/account-owners",
  {
    method: "POST",
    headers: {
      "Authorization": `Bearer ${tenantToken}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      id: "d290f1ee-6c54-4b01-90e6-d701748f0851",  // V4 UUID recommended
      account_owner_type: "INDIVIDUAL",            // INDIVIDUAL or ENTITY
    }),
  }
);

The id you provide becomes the account_owner_id in all subsequent API calls.

Provisioning strategy

New users: Create the Account Owner during onboarding, when the user creates their account in your system. Only IDs needed.

Existing users: Both API and file ingestion are available for backfilling existing Account Owner data.

📘

Account creation is optional for the SDK

The SDK does not require an Account. You may need Accounts later for transaction reporting. See Accounts API.

08 · Generate an Account Owner-scoped token Required

The SDK needs a token scoped to a single Account Owner.

// Server-side — Node.js
const aoTokenResponse = await fetch(
  "https://api.multi1.enterprise.taxbit.com/v1/oauth/account-owner-token",
  {
    method: "POST",
    headers: { "Content-Type": "application/x-www-form-urlencoded" },
    body: new URLSearchParams({
      grant_type:       "client_credentials",
      client_id:        process.env.TAXBIT_CLIENT_ID,
      client_secret:    process.env.TAXBIT_CLIENT_SECRET,
      tenant_id:        process.env.TAXBIT_TENANT_ID,
      account_owner_id: "d290f1ee-6c54-4b01-90e6-d701748f0851",  // from Step 07
    }),
  }
);

const { access_token: aoToken } = await aoTokenResponse.json();
// Pass aoToken to your client. Use it as bearerToken in Step 05

Token expiration

Both the tenant token and Account Owner token are valid for 24 hours. If a token expires mid-session, API calls return 401 Unauthorized. Handle this in your onError callback by requesting a fresh token from your backend and re-initializing the SDK.


C · Customize & enhance

Production polish. Callbacks, styling, pre-fill, and more.

09 · Wire up callbacks Recommended

Hook into the SDK lifecycle for analytics, routing, and error handling.

<TaxbitQuestionnaire
  bearerToken={bearerToken}
  questionnaire="W-FORM"
  onProgress={(p) => analytics.track('tax_step', p)}
  onSubmit={(data) => console.log('submitting', data)}
  onSuccess={(data) => router.push('/onboarding/done')}
  onError={(err) => Sentry.captureException(err)}
  onSettled={() => setSubmitting(false)}
/>

See Component and hook reference for the Progress object and all callback signatures.

🚧

Do not rely on client-side callbacks for compliance state

Users can close their browser before onSuccess fires. Do not use client-side callbacks to update critical compliance records in your database. Use webhooks for definitive status changes.

📘

Handling re-submissions

Check statusData.needsResubmission via the useTaxbit hook on login or key flows. Surface a banner or blocking screen when true. Use adaptiveMode="skipEdit" (not "skipLock") for re-submission so users can update changed info. Only notify when action is needed.

10 · Style the SDK to match your brand Recommended

Pick a starter stylesheet and override what you need.

// Three built-in options
import '@taxbit/react-sdk/style/inline.css';   // fully styled (recommended)
import '@taxbit/react-sdk/style/basic.css';    // neutral baseline
import '@taxbit/react-sdk/style/minimal.css';  // almost unstyled
/* Override to match your brand */
.taxbit-button {
  background: #0B1B33;
  border-radius: 8px;
}
.taxbit-input:focus {
  outline: 2px solid #2EE5C8;
}

Design tip

Use a lightweight frame around the SDK. Avoid popups, cookie consent banners, or notification overlays that might confuse the user or obstruct the form. Align fonts, colors, and layout to match your native design.

See Component and hook reference for the full CSS guide, and Adaptive mode for branded examples.

Mobile webview embedding

The Taxbit React SDK is a web-based solution built with HTML5 and React. For native mobile apps, load the SDK inside a webview. The SDK handles the full tax documentation flow within the webview, and your native app controls the surrounding experience.

How it works:

  1. Prepare a webpage that hosts the TaxbitQuestionnaire component along with your JavaScript code. This page will listen to SDK events (callbacks).
  2. Load this webpage in a webview and set up native code bindings so your app can receive events from the SDK.
  3. Configure your JavaScript to call native callback methods when the SDK fires events like onSuccess, onError, or onProgress.

Webview components by platform:

PlatformComponentDocs
React Nativereact-native-webviewGitHub
Flutterwebview_flutterpub.dev
iOS (native)WKWebViewApple Developer
Android (native)android.webkit.WebViewAndroid Developer

Communicating between the webview and your native app:

For Android, use JavaScript interface bindings to call native Android code from your webview. See the official Android documentation on binding JavaScript to Android code.

For iOS, use WKUserContentController to set up message handlers that receive events from JavaScript running in the webview. See the Apple documentation on WKUserContentController.

Performance and caching

Pre-warm the webview. Webviews take time to spin up. Instantiate and load the URL off-screen before the user navigates to the tax documentation screen. On Android Custom Tabs, call CustomTabsClient.warmup().

Deferred rendering. To avoid dropping UI frames (jank), delay rendering heavy webview content until native screen animations and transitions are completely finished.

Enable DOM storage. Set domStorageEnabled (Android) or equivalent local storage settings so the SDK can cache assets locally for faster load times on repeat visits.

User experience

Fallback handling. Always handle network connection losses gracefully. Intercept loading errors (onReceivedError on Android, didFailProvisionalNavigation on iOS) and present a clean, native "Offline" screen rather than a generic browser error page.

Visual continuity. Web content often pops into view abruptly. Mask this by implementing a native progress bar or shimmer skeleton screen that stays active until the page completely finishes rendering.

Responsive viewports. Ensure the embedded HTML contains a mobile-first viewport meta tag: <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"> to prevent unwanted desktop-style layout sizing.

Form input handling. On mobile, keyboard behavior can obscure form fields. Test that the webview scrolls correctly when the keyboard opens, especially for address and TIN input fields.

11 · Pre-fill form data you already have Optional

Pass data you already collected via the data prop so users only confirm what's already there.

const prefillData = {
  accountHolder: {
    name: 'Jane Smith',
    isUsPerson: true,
    accountOwnerType: 'INDIVIDUAL',
    address: {
      firstLine: '742 Evergreen Terrace',
      city: 'Springfield',
      stateOrProvince: 'IL',
      postalCode: '62704',
      country: 'US',
    },
  },
};
<TaxbitQuestionnaire data={prefillData} bearerToken={bearerToken} questionnaire="W-FORM" />

The data prop takes priority over server-fetched data. See Component and hook reference for the full type.

12 · Enable PDF download Optional

After submission, give users a download of their completed W-9, W-8, or Self-Cert. DPS does not support PDF.

import { useTaxbit } from '@taxbit/react-sdk';

function DownloadButton({ bearerToken }) {
  const {
    canGetDocumentUrl, generateDocumentUrl,
    isGeneratingDocumentUrl, documentUrl,
  } = useTaxbit({ bearerToken, questionnaire: 'W-FORM' });

  useEffect(() => {
    if (canGetDocumentUrl) generateDocumentUrl();
  }, [canGetDocumentUrl]);

  if (!canGetDocumentUrl) return null;
  return documentUrl
    ? <a href={documentUrl} download>Download tax form</a>
    : <button disabled>Generating PDF…</button>;
}

Where to go next