Integration Guide

Collect W-9, W-8 (BEN, BEN-E, IMY), MRDP (DAC7), CRS, and CARF tax documentation inside your React application with a drop-in, fully customizable component. Submitted data flows into the Taxbit platform, undergoes TIN matching where applicable, and feeds end-of-year information returns. Completed forms are available from the Taxbit Dashboard and the Tax Documentation API.

The SDK supports three questionnaire types:

QuestionnaireUse it for
Forms W-8 / W-9 (W-FORM)Collect and validate Forms W-8 and W-9 ahead of payment and reporting for 1099-B, DIV, INT, and more.
Digital Platform Seller (DPS)Satisfy MRDP obligations under DAC7 (EU), and equivalents in the UK, New Zealand, and Canada.
Self-Certification (SELF-CERT)Collect CRS, CARF, and DAC8 self-certifications based on OECD guidance for global reporting.

You'll pick the one that fits your users under Configure for your use case.

Set up locally

Render the SDK in demo mode to verify it works in your app. Demo mode requires no token and makes no requests to Taxbit.

Install the SDK

npm install @taxbit/react-sdk

Compatible with React 16–19 and TypeScript 5.

Render in demo mode

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

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

Set questionnaire to "DPS" or "SELF-CERT" to render the other forms. onProgress and onSubmit fire in demo mode, so you can inspect the data the SDK collects.

What you should see

The component renders the questionnaire as a multi-step form: a progress indicator, one group of questions per step, inline validation, and Back / Next / Submit controls. onProgress and onSubmit fire as the user moves through it, so you can confirm data is flowing.

The styling is Taxbit's default, not a fixed design. The form is plain semantic HTML with taxbit- class names — point it at your own stylesheet to match your product. See Style it to your brand.

If the form doesn't render, verify the stylesheet import resolved and your React version is supported. Next, connect your backend to submit real data.

Connect your backend

The SDK authenticates with a bearer token scoped to a single Account Owner — the user you're collecting documentation from. Mint the token on your server; token requests from the browser are rejected.

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.

Non-US tenants and proxied networks. EU-provisioned tenants pass region="EU" (the default is "US"); the server-side API host is region-specific too. Where direct access to Taxbit is restricted, route requests through your own gateway with proxyDomain, plus proxyHeaders for custom auth (your proxy must strip them before forwarding).

Create an Account Owner Required

Create an Account Owner for each user you collect from. Authorize this tenant-wide call with a tenant-scoped token from POST /v1/oauth/token. Only id and account_owner_type are required.

MethodEndpoint
POST/v1/account-owners
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. For new users, create the Account Owner during onboarding, when the user creates their account in your system — only the ID is needed. For existing users, both the API and file ingestion are available for backfilling Account Owner data.

Account creation is optional for the SDK. The SDK doesn't require an Account. You may need Accounts later for transaction reporting — see the Accounts API.

Mint an Account Owner token

Exchange your credentials for an Account Owner–scoped token and pass access_token to your client.

const { access_token } = 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: accountOwnerId,
    }),
  }
).then((r) => r.json());

Token expiration

If a token expires mid-session, API calls return 401 Unauthorized and surface through your onError callback. See Handling token expiration for how to detect and recover from it.

Render with real data

Replace the demoMode prop with the bearerToken prop. The same component now submits to Taxbit:

<TaxbitQuestionnaire
  questionnaire="W-FORM"
  bearerToken={accountOwnerToken}
  onSuccess={handleSuccess}
/>

Submissions appear in your Taxbit Dashboard and are retrievable from the tax-documentation-status endpoint. onSuccess fires when Taxbit receives the submission, not when validation completes — see Handle validation and status.

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 renders but API calls will fail — check your browser's network and console errors and your onError handler before testing in production.

Configure for your use case

With real data flowing, shape the flow to fit your users: which questionnaire you need, and how to avoid asking for data you already have.

Pick your questionnaire

Each pattern below leads with the situation that determines the configuration. If more than one applies to your user base — for example, U.S. and non-U.S. payees — render the component multiple times with different questionnaire values per Account Owner.

Paying U.S. persons subject to 1099 reporting

W-FORM. Collect Form W-9 from U.S. individuals or entities who'll receive a 1099 at year-end. Use this whenever you need a certified U.S. TIN before making a reportable payment.

PropSetting
questionnaire"W-FORM"
realTimeTinValidationtrue if your tenant is configured for RTT — surfaces TIN mismatches at submission rather than at year-end.
treatyClaimsOmit — treaty claims don't apply to W-9 filers.

Watch for: a returning tinStatus of MISMATCH or INVALID_DATA after submission — these need a B-notice flow. See TIN validation.

Paying foreign persons U.S.-source income (FDAP)

W-FORM. Collect Form W-8BEN or W-8BEN-E. If the payee may claim reduced withholding under a tax treaty, enable treatyClaims to surface the additional questions about treaty country, article, and claimed rate.

PropSetting
questionnaire"W-FORM"
treatyClaimstrue if any of your foreign payees may claim treaty benefits. Safe to leave on universally — payees not claiming a treaty move through the questions without committing to anything.
realTimeTinValidationNo effect — RTT applies only to W-9 submissions.

Watch for: treatyClaimStatus: 'INVALID' and the TREATY_COUNTRY_MISMATCH issue type both mean the treaty claim won't apply as submitted. The needsResubmission flag on wFormQuestionnaire tracks whether the user needs to return. See validation and status.

Collecting CRS, CARF, or DAC8 self-certification

SELF-CERT. Collect tax residences, citizenship, and TINs from individuals or entities on platforms subject to CRS, CARF, or DAC8 reporting. The same questionnaire serves both, with the payload shape differing by entity type.

PropSetting
questionnaire"SELF-CERT"
data.accountHolder.isIndividualtrue for individuals; false for entities. Entities also need selfCertificationAccountType set to "FINANCIAL_INSTITUTION", "ACTIVE_NON_FINANCIAL_ENTITY", or "PASSIVE_NON_FINANCIAL_ENTITY".
languageDefaults to en-GB. Set explicitly for non-English markets.

Watch for: tax residences in high-risk jurisdictions trigger an additional accountHolderTaxResidenciesConfirmation step. Controlling-person data on entity flows cannot be pre-populated — those questions are always shown, even with adaptive mode enabled.

Running a digital platform with MRDP reporting obligations

DPS. Collect seller information for DAC7 (EU) and equivalents in the UK, New Zealand, and Canada. The SDK collects tax identification, address, business registration, and (where applicable) VAT.

PropSetting
questionnaire"DPS"
languageDefaults to en-GB. Set per-seller based on locale; full EU language coverage is supported.

Watch for: VAT validation via VIES is asynchronous — vatStatus may return 'PENDING' on first submission and resolve later. See VAT validation. DPS submissions don't have a downloadable PDF — canGetDocumentUrl on the hook will be false.

Adaptive mode: skip pre-filled questions

Use Adaptive mode when you already collect user data upstream — during onboarding, KYC, KYB, or account maintenance — and want the SDK to ask only for what's still missing, invalid, or required for the tax form.

Think of it as a bridge between your application flow and Taxbit's tax documentation flow: you keep your existing upstream experience, pass known data in through the data prop, and the SDK shortens the questionnaire by hiding fields already satisfied with valid values. It evaluates each field independently:

  • Valid values hide the question.
  • Invalid or incomplete values are shown so the user can correct them.
  • Required fields still appear when missing.

Note: Adaptive mode reduces duplicate data entry, but it doesn't remove required certification, confirmation, or review steps. Some sections also can't be pre-populated — controlling-person data in certain Self-Cert entity flows, for example.

What it does and doesn't do

It does:

  • Hide questions for fields you already provided with valid values.
  • Shorten the flow so users focus only on what still needs attention.
  • Support different review experiences depending on whether skipped values should be locked or editable.

It doesn't:

  • Bypass required tax logic or certification requirements.
  • Silently accept invalid upstream data — invalid or incomplete values are still shown for correction.
  • Guarantee every section can be pre-populated — some are always collected directly in the SDK.

When to use it

Adaptive mode is a strong fit when you already collect some or most of the same information upstream and want tax documentation to feel like a continuation of your existing flow rather than a separate questionnaire. Common cases:

  • End-of-onboarding tax documentation after KYC or KYB.
  • Existing-user resubmission or change-in-circumstance flows.
  • Account settings or maintenance flows where you re-open the SDK with as much prior data preserved as possible.

Choose a mode

<TaxbitQuestionnaire
  questionnaire="W-FORM"
  adaptiveMode="skipLock"
  bearerToken={token}
  data={{
    accountHolder: {
      isUsPerson: true, usAccountType: "INDIVIDUAL",
      name: "Jane Doe", tin: "776568989",
      address: { firstLine: "123 Main St", city: "Seattle",
        stateOrProvince: "WA", postalCode: "98101", country: "US" },
    },
  }}
/>
ModeIn the flowOn the review screenBest for
full (default)Nothing skipped; supplied data is pre-filledAll fields editablePrefill only, without hiding questions
skipLockQuestions with valid data are hiddenSkipped fields are lockedOnboarding flows where upstream data should change only when strictly necessary
skipEditQuestions with valid data are hiddenAll fields remain editableResubmission or maintenance flows where users may need to adjust prior values

How skip logic works

Adaptive reads three signals per field: whether it's present in data, whether the value is valid, and whether it's required for the form type.

What you passIn the flowReview (skipLock)
Valid valueHiddenLocked
Invalid or incompleteShown to fixEditable
"" on an optional fieldHiddenLocked
"" on a required fieldShown — never skipped on ""Editable
Omitted (optional)HiddenEditable — generally nothing to lock
Omitted (required)ShownEditable

Invalid or incomplete data — a partial address, an invalid postal code, a wrong date format, a malformed TIN — is always shown so the user can correct it.

Empty string vs. omitted

Pass "" only for a field you already showed the user in your own UI and they chose to leave blank; the SDK reads it as "asked and intentionally skipped" and won't ask again. This applies to optional fields only — a required field with "" is treated as missing and still shown.

Don't pass "" to shorten the flow for a field the user never saw. Some fields — a W-8 mailing address, a W-8 U.S. TIN — are optional in the SDK but should still be offered; an empty string there produces a form that's valid in the SDK but invalid under tax rules.

FTIN

Non-U.S. TINs with syntax warnings are still skipped (and locked under skipLock). Setting ftinNotLegallyRequired: true overrides the FTIN entirely — the SDK treats the field as not required.

Example: what the user still sees

Suppose you collected a user's name, address, and TIN during onboarding and passed those into the SDK. If the values are valid:

  • The user doesn't re-enter them in the SDK.
  • The SDK asks only for fields that are still missing, invalid, or required for the tax form.
  • The user still completes any required certifications, confirmations, or always-collected sections.

The more complete and valid your upstream data, the shorter the SDK flow — which is why Adaptive mode works best paired with a clear upstream data strategy.

Prefill data by form type

Adaptive reads the data prop. The fields it accepts differ by form type — expand a shape to see what you can pre-fill. Which props to set for each questionnaire is covered under Pick your questionnaire.

W-9 — Individual
{
  "accountHolder": {
    "isUsPerson": true,
    "usAccountType": "INDIVIDUAL",
    "name": "Jane Doe",
    "tin": "776568989",
      "address": {
        "firstLine": "123 Main St",
        "secondLine": "",
        "city": "Seattle",
        "stateOrProvince": "WA",
        "postalCode": "98101",
        "country": "US"
      }
  }
}
W-9 — Entity (C Corporation)
{
  "accountHolder": {
    "isUsPerson": true,
    "usAccountType": "C_CORPORATION",
    "name": "Martinez Corporation",
    "dbaName": "Martinez Solutions",
    "tin": "776568989",
      "address": {
        "firstLine": "123 Main St",
        "secondLine": "",
        "city": "Seattle",
        "stateOrProvince": "WA",
        "postalCode": "98101",
        "country": "US"
      }
  }
}
W-8BEN
{
  "accountHolder": {
    "isUsPerson": false,
    "accountOwnerType": "INDIVIDUAL",
    "name": "Maria Fernandez",
    "ftin": "A1234567",
    "address": {
      "firstLine": "45 Calle Real",
      "secondLine": "Apt 3",
      "city": "Madrid",
      "stateOrProvince": "MD",
      "postalCode": "28001",
      "country": "ES"
    },
    "mailingAddress": {
      "firstLine": "PO Box 123",
      "secondLine": "",
      "city": "Madrid",
      "stateOrProvince": "MD",
      "postalCode": "28002",
      "country": "ES"
    },
    "mailingAddressIsDifferent": true,
    "countryOfCitizenship": "ES",
    "dateOfBirth": "01/01/1990",
    "ftinNotLegallyRequired": false
  }
}
W-8BEN-E
{
  "accountHolder": {
    "isUsPerson": false,
    "accountOwnerType": "ENTITY",
    "countryOfCitizenship": "US",
    "foreignAccountType": "CORPORATION",
    "name": "Fernandez Consulting Group",
    "ftin": "B9876543",
    "tin": "",
    "address": {
      "firstLine": "100 Business Rd",
      "secondLine": "Suite 500",
      "city": "Barcelona",
      "stateOrProvince": "BC",
      "postalCode": "08001",
      "country": "ES"
    },
    "mailingAddress": {},
    "mailingAddressIsDifferent": false,
    "ftinNotLegallyRequired": false
  }
}
Self-Certification — Individual
{
  "accountHolder": {
    "isIndividual": true,
    "name": "Ray Holt",
    "address": {
      "firstLine": "100 Harbour Road",
      "secondLine": "",
      "city": "Dublin",
      "stateOrProvince": "",
      "postalCode": "D02",
      "country": "IE"
    },
    "countryOfCitizenship": "IE",
    "dateOfBirth": "05/31/1994",
    "taxResidences": [
      { "country": "IE", "tin": "2342344T" }
    ]
  }
}
Self-Certification — Managed Investment Entity

Controlling-person data cannot be pre-populated at this time.

{
  "accountHolder": {
    "isIndividual": false,
    "selfCertificationAccountType": "FINANCIAL_INSTITUTION",
    "financialInstitutionType": "INVESTMENT_ENTITY",
    "investmentEntityManaged": true,
    "entityType": "TRUST",
    "name": "Managed Investments Ltd.",
    "address": {
      "firstLine": "100 Harbour Road",
      "secondLine": "",
      "city": "Dublin",
      "stateOrProvince": "",
      "postalCode": "D02",
      "country": "IE"
    },
    "countryOfCitizenship": "IE",
    "taxResidences": [
      { "country": "IE", "tin": "2342344T" },
      { "country": "AU", "tin": "51824753556" }
    ]
  }
}

Skip server-side prefill

By default, <TaxbitQuestionnaire /> fetches the account owner's prior submission on mount and prefills the form with it, so a returning user lands on a completed summary. For most products that's what you want — it's the same saved data Adaptive mode compares against. For stricter security postures, the prepopulateWithSavedData prop opts out of that fetch.

Setting prepopulateWithSavedData={false}:

  • Skips the GET /tax-documentation/submissions call entirely — no prior PII is sent over the wire on mount. (The SDK normally appends ?unmask=true&questionnaire=… to this same path; with the prop disabled, the request isn't made at all.)
  • Forces the form to start on step one — the user walks the questionnaire from the beginning, even if they previously submitted a completed form.
  • Leaves the status fetch unaffected — useTaxbit().statusData still works exactly as before; status, issues, expiration, and curing signals are all still available.
  • Leaves submission unaffected — POST /tax-documentation/submissions works the same. Submitting populates the user's record as a fresh submission.

Omitting the prop preserves today's behavior for every existing integration — this is an opt-in change.

ValueEffect
prepopulateWithSavedData={true} (default)Fetches the prior submission, prefills the form, and routes returning users to the summary.
prepopulateWithSavedData={false}Doesn't fetch the prior submission. The form starts fresh on step one.

When to use it

Set prepopulateWithSavedData={false} when:

  • You gate the SDK behind step-up auth (2FA, recent-auth) and don't want previously collected data rendered into the DOM during the session.
  • Your security posture requires the SDK to display only data the user enters in the current authenticated session.
  • The user is expected to re-attest from scratch — compliance-driven re-collection or periodic reverification.

Leave it at the default for the standard onboarding pattern, where returning users review their prior submission and continue from where they left off.

Usage

<TaxbitQuestionnaire
  questionnaire="W-FORM"
  bearerToken={accountOwnerToken}
  prepopulateWithSavedData={false}
  onError={(err) => reportToSentry(err)}
  onSuccess={() => router.push('/done')}
/>

That's the whole integration — no other props or callbacks change because of this flag.

Interaction with other props

data (host-supplied prefill). This prop gates server-saved data only — the submission Taxbit has on file. It does not suppress prefill you pass via data. With prepopulateWithSavedData={false} and a populated data prop, the SDK skips the server fetch but still prefills from data. For a fully blank form, omit data.

adaptiveMode. Adaptive mode compares submitted state against the host-supplied data or the server-fetched submission. With the server side turned off, it has only data to work from: no data means nothing to compare against, so the user sees every field (same as adaptiveMode='full'); a populated data means it skips or locks those fields only. If your goal is "no prior PII," Adaptive mode against a data prop you control is still consistent with that.

useTaxbit. statusData is unaffected — it's metadata from a different endpoint, not PII. But serverData returns an empty object when prepopulateWithSavedData={false}, and refreshSubmission() is a no-op since there's nothing fetched to refresh. Account for the empty case if any UI outside the SDK reads serverData.

Pitfalls

  • The prop name means server-saved data, not all prefill. It does not suppress the data prop. If a security review hinges on "no prefill at all," set the flag and omit (or audit) what you pass to data.
  • The prior submission still exists server-side. This flag changes only what the SDK fetches and renders — it doesn't delete or hide prior data on the Taxbit side. A token capable of rendering the SDK can still retrieve the prior submission via a direct API call.

Handle validation and status

TIN matching with the IRS, VAT validation via VIES, and downstream changes all resolve after the user submits.

Received vs. validated

onSuccess is the callback the SDK fires once a submission reaches Taxbit and is accepted. It confirms receipt — not that the TIN matched, the VAT validated, or the form is final.

Validation continues after the user leaves:

  • W-9 — TIN matched against the IRS
  • DPS — VAT validated against VIES

Either can take minutes to hours, so don't mark a form "complete" on onSuccess alone. Read the final result from tinStatus / vatStatus, covered next.

Read status with the useTaxbit hook

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

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

if (statusData?.wFormQuestionnaire?.tinStatus === 'PENDING') {
  return <Badge>Validation in progress</Badge>;
}

Both fields begin PENDING and resolve after submission:

  • tinStatus (W-9, IRS match) — MISMATCH and INVALID_DATA feed a B-notice flow; a VALID_*_MATCH clears it. realTimeTinValidation attempts the match at submission and reflects it inline.
  • vatStatus (DPS, VIES) — resolves to VALID, INVALID, INSUFFICIENT_DATA, NOT_REQUIRED, or NON_EU.

See the reference for every value.

Respond to changes with webhooks

Submissions can change state long after the user is gone — a W-8 may need resubmission after a change in circumstances, a TIN may flip from VALID to MISMATCH on a re-check, an issue may be cured in the Taxbit Dashboard. These surface as webhook events.

Use the Webhooks Guide for the full event taxonomy. A few notes specific to SDK integrations:

  • The account-owner status webhook fires for any change to the status object, not just user-initiated submissions — don't trigger user-facing notifications directly from it.
  • To detect a genuinely new submission, compare the document ID from the status API: a changed ID means new data; the same ID means existing data was re-evaluated.
  • Delivery retries; if it ultimately fails, file a support ticket to redrive events, and keep your own monitoring on top of Taxbit's.

When needsResubmission is set, route the user back to the same component with adaptiveMode="skipEdit".

Cure post-submission issues

Some W-8 validation issues can be resolved without re-collecting the whole form. When statusData surfaces an OPEN curable issue, route the user to <TaxbitCuringDocumentation /> instead of the full questionnaire — it gathers only the evidence and reasonable explanation needed to clear the open issue.

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

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

if (!isLoading && needsCuringDocumentation) {
  return <TaxbitCuringDocumentation bearerToken={bearerToken} onSuccess={refresh} />;
}

Gate the mount on needsCuringDocumentation. Curing is W-8 only — W-9 users with issues go back through <TaxbitQuestionnaire /> with adaptiveMode="skipEdit". See the Curing Integration Guide for the full walkthrough: when to use it, curable issue types, what the user sees, and the post-submission lifecycle.

Offer a PDF download on the confirmation screen

This sits at the end of the flow — the confirmation screen you render after onSuccess, not your styling layer. Available for W-Form and Self-Certification submissions, not DPS.

useTaxbit mints a short-lived download URL; gate the link on canGetDocumentUrl.

const { canGetDocumentUrl, generateDocumentUrl, documentUrl } =
  useTaxbit({ bearerToken, questionnaire });

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

return documentUrl ? <a href={documentUrl} download>Download form</a> : null;

Customize and ship

Style it to your brand

Semantic HTML with namespaced classes. Import a stylesheet and override what you need.

import '@taxbit/react-sdk/style/inline.css'; // or 'basic.css' / 'minimal.css'
.taxbit-button { background: #0B1B33; border-radius: 8px; }
.taxbit-input:focus { outline: 2px solid #2EE5C8; }

Support mobile

There's no native SDK — render in a webview and bridge callbacks to native code, reusing the same token flow. Host a page that posts each callback to whichever bridge is present:

function notifyNative(event, payload) {
  const msg = JSON.stringify({ event, payload });
  window.ReactNativeWebView?.postMessage(msg);              // React Native
  window.webkit?.messageHandlers?.taxbit?.postMessage(msg); // iOS WKWebView
  window.TaxbitBridge?.postMessage(msg);                    // Android interface
}

<TaxbitQuestionnaire
  questionnaire="W-FORM"
  bearerToken={bearerToken}
  onSuccess={(d) => notifyNative('success', d)}
  onError={(e) => notifyNative('error', e)}
/>

Load that page in your platform's webview:

  • React Nativereact-native-webview
  • iOSWKWebView, with WKUserContentController message handlers
  • Androidandroid.webkit.WebView, with a JavaScript interface

For production:

  • Pre-warm the webview off-screen
  • Enable DOM storage
  • Handle load errors with a native offline screen
  • Set the viewport meta tag:
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">

Languages

Set language to pre-select the locale; account owners can also switch via an in-form dropdown (hideable with CSS). The language prop accepts the full Locale set (53 tags); the in-form picker shows a subset — roughly 45 for DPS and Self-Certification and 19 for W-Form. See Supported languages for the full list of locale codes.

Next steps