Curing Integration Guide

Resolve specific W-8 validation issues with a focused component — without re-collecting the full form.

The Integration Guide collects tax documentation. This guide covers the post-submission counterpart: clearing specific W-8 validation issues with <TaxbitCuringDocumentation /> — a separate component from <TaxbitQuestionnaire />.

After a W-8 is submitted, validation can flag issues — a US address on a foreign filer, a treaty country that doesn't match the residency, an unsupported PO Box. The curing component is a focused remediation flow that surfaces only the open issues and gathers the specific evidence and explanation needed to clear each one, instead of re-collecting the entire form.

If you've already integrated the questionnaire and handle needsResubmission, you have most of what this guide builds on. The token flow, stylesheet, and webhook are the same — the only new pieces are one component and one hook signal.

You already haveCuring adds
Account Owner token flow— same token
@taxbit/react-sdk + a stylesheet import— same import; shared taxbit-* namespace
ACCOUNT_OWNER_TAX_DOCUMENTATION_STATUS webhook— same event drives the curing entry point
<TaxbitQuestionnaire /><TaxbitCuringDocumentation /> + needsCuringDocumentation

When to reach for curing

The curing widget is the right surface when all three are true:

  • The user has a prior W-8 submission (dataCollectionStatus: "COMPLETE").
  • The submission has at least one issue with status: "OPEN" that the curing flow can resolve.
  • You'd rather have the user fix the specific issue than walk the whole questionnaire again.

If the submission isn't complete, or the issue isn't curable, route the user back through <TaxbitQuestionnaire /> with adaptiveMode="skipEdit" instead.

Curable issue types

Curable issues are W-8 only — W-9 submissions don't surface curable issues today. Which types apply depends on the document type:

Issue typeW-8BENW-8BEN-EW-8IMY
US_INDICIA
TREATY_COUNTRY_MISMATCH
CARE_OF_PERMANENT_ADDRESS
PO_BOX_PERMANENT_ADDRESS

Watch for: address-shape issues on individual W-8BEN surface in statusData.wFormQuestionnaire.issues but aren't resolvable through curing. Route those filers back through the questionnaire. See the Component and Hook Reference for the full CurableIssueType definition.

Issue status

StatusSurfaces in curing?
OPENYes — actionable; user can submit a cure.
IN_REVIEWNo — a prior cure is pending tax-manager review. The user cannot submit again.
RESOLVEDNo — already cleared.

Set up locally

Demo mode renders the component against a synthesized issue list — no token, no network calls. Assumes you've already installed the SDK and imported a stylesheet per the Integration Guide.

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

<TaxbitCuringDocumentation
  demoIssueTypes={['US_INDICIA', 'TREATY_COUNTRY_MISMATCH']}
  onSubmit={(submission) => console.log(submission)}
/>

demoIssueTypes is the demo discriminator. Pass any subset of CurableIssueType (or an empty array for the no-issues render). Status is assumed OPEN for every demo issue; doc type is fixed to W-8BEN-E. The demo onSubmit receives the same ClientCuringSubmission shape production callbacks do, so demo harnesses don't special-case form state.

Gate the mount

The widget is conditional, not a permanent page. Gate it on useTaxbit().needsCuringDocumentation, reusing the same Account Owner token you mint for the questionnaire.

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

function CuringPage({ bearerToken }) {
  const { needsCuringDocumentation, isLoading } = useTaxbit({
    bearerToken,
    questionnaire: 'W-FORM',
  });

  if (isLoading) return <Spinner />;
  if (!needsCuringDocumentation) return null;

  return (
    <TaxbitCuringDocumentation
      bearerToken={bearerToken}
      onSuccess={() => router.push('/done')}
      onError={(err) => Sentry.captureException(err)}
    />
  );
}

Check isLoading first. The predicate is false while statusData is undefined, so without the loading check there's a brief flash where the widget hides before the real answer arrives. The component also fail-safes to null when there's no OPEN curable issue (with a dev-mode warning), but gating first saves a status-fetch round-trip.

Two places this mount tends to live: a user-facing remediation page ("your tax documentation needs attention" badge in settings or the payout area), or a re-collection inbox triggered by your ACCOUNT_OWNER_TAX_DOCUMENTATION_STATUS webhook handler when the new state has an OPEN curable issue.

Render with real data

The component mirrors <TaxbitQuestionnaire />'s three-way prop discriminator — demo, region + optional staging, or proxy. Exactly one shape applies per call site.

Region (default)

<TaxbitCuringDocumentation
  bearerToken={accountOwnerToken}
  region="US"                          // or 'EU'
  staging={false}                      // true to hit the staging cluster
  language="en-us"
  poweredByTaxbit={true}
  loadingComponent={<Spinner />}
  onSuccess={(submission) => { /* server confirmed receipt */ }}
  onError={(err) => { /* report */ }}
  onSettled={(submission) => { /* fires after success or error */ }}
/>

Through a proxy

<TaxbitCuringDocumentation
  bearerToken={accountOwnerToken}
  proxyDomain="https://taxbit-proxy.your-corp.com"
  proxyHeaders={{ 'x-correlation-id': '...' }}
  onSuccess={...}
  onError={...}
  onSettled={...}
/>

authorization and content-type are reserved on proxyHeaders — your proxy must strip and re-add them. region/staging and proxyDomain are mutually exclusive. Full prop tables are in the Component and Hook Reference.

What the user sees

A single page with sections rendered in this order:

  1. Intro + issue summary — a short explanation and a per-issue list of what's open against this submission.
  2. Step 1 — Upload documentary evidence. One file picker. Every curable issue type asks for the file.
  3. Step 2 — Reasonable explanation. Visible only when the user has an open US_INDICIA issue. The user picks one of six categories; two reveal extra fields:
    • DO_NOT_MEET_SUBSTANTIAL_PRESENCE_TEST reveals the substantial-presence-test calculation (current-year, first- and second-preceding-year day counts; the widget shows the weighted total live as the user types).
    • CLOSER_CONNECTION_EXCEPTION reveals closer-connection certification (a certification checkbox, country, free-text reason).
    • STUDENT, TEACHER_OR_TRAINEE, DIPLOMAT, and SPOUSE_OR_CHILD need no extra fields.
  4. Step 3 — Review and consent. A final confirmation block before submit.

You receive the result as ClientCuringSubmission in onSuccess, onSettled, and the demo onSubmit — the same shape across environments. See the reference for the full payload.

Handle the result

onSuccess fires when Taxbit's server accepts the multipart POST — not when the cure has been re-reviewed. A tax manager still has to mark the issue RESOLVED; expect minutes to days. An OPEN issue submitted via curing flips to IN_REVIEW; while IN_REVIEW the widget renders null and the filer can't submit again. The status then moves to RESOLVED (cleared) or back to OPEN (rejected, can be submitted again).

The hook reads status once on mount, so after a successful submit call useTaxbit().refresh() before reading derived state:

const { refresh } = useTaxbit({ bearerToken, questionnaire: 'W-FORM' });

<TaxbitCuringDocumentation
  bearerToken={bearerToken}
  onSuccess={async () => {
    await refresh();
    router.push('/account');
  }}
/>

For reading statuses across the hook, the status endpoint server-to-server, and the ACCOUNT_OWNER_TAX_DOCUMENTATION_STATUS webhook — including systematic backend reads of who has submitted a cure — see Reading curing statuses.

What's not supported

  • W-9 curing — W-9 submissions don't surface curable issues today; route W-9 users with issues back through <TaxbitQuestionnaire />.
  • Address-shape issues on individual W-8BENCARE_OF_PERMANENT_ADDRESS and PO_BOX_PERMANENT_ADDRESS appear as issues on individual W-8BEN submissions but aren't resolvable through this flow.
  • onProgress — there's no step-by-step progress callback. The form is short and section-based.
  • PDF download — curing submissions don't have a separate downloadable PDF. useTaxbit().canGetDocumentUrl still reflects the underlying W-8 PDF, not the curing submission.

Styling

Uses the same taxbit-* CSS namespace as <TaxbitQuestionnaire />. The same imported stylesheet (inline.css, basic.css, or minimal.css) styles both widgets — no separate CSS file. Curing layout lives under the shared .taxbit-section* classes, so brand overrides you've already written apply automatically.

Next steps