feat(Contractor.SignatureForm): add contractor W-9 signature form#2299
Closed
serikjensen wants to merge 5 commits into
Closed
feat(Contractor.SignatureForm): add contractor W-9 signature form#2299serikjensen wants to merge 5 commits into
serikjensen wants to merge 5 commits into
Conversation
Add the SignatureForm component and useContractorSignatureForm headless hook for signing contractor documents (W-9). The hook builds a dynamic zod schema and field metadata from the document's fields[] payload, synthesizes the seven API tax-classification checkboxes into a single radio group with conditional LLC/other sub-fields, and serializes back to the API's key/value shape on submit. Redacted SSN/EIN values returned by the API are treated as on-file: the input is seeded empty with the masked value as a placeholder, required validation is waived, and the field is omitted from the sign payload when left untouched so the mask is never written back. Co-authored-by: Cursor <cursoragent@cursor.com>
…yload Fold in W-9 fidelity fixes: - Derive each field's input variant from the API data_type so exemption_from_FATCA renders as its text reporting code (4b) rather than a checkbox; swap the mock/i18n to match. - Omit the date field from the sign payload so the API auto-fills the signing date in its own locale-correct format; drop the now-unused SIGNED_DATE_FIELD export. - Send signedByIpAddress in the sign request body, matching the employee/company sign flows (IP supplied by the partner proxy header). Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
a0898b2 to
9507110
Compare
…r types Only useContractorSignatureForm, its error codes, and the types a partner needs to consume the result (props/result/ready, sections, bound-field types, form data, W9Section) are exported from the package entry. The W-9 wire-format helpers (buildW9FieldDescriptors, buildW9Defaults, serializeW9Fields, isW9Document, createContractorSignatureFormSchema, buildContractorSignatureFields) and raw API-key constants are implementation details — dropped from the entry and tagged @internal so they no longer surface in the generated reference docs. Co-authored-by: Cursor <cursoragent@cursor.com>
…alidation - Seed the LLC classification code default from the API tax_classification field - Add SSN/EIN format validation and input formatting; accept the N/A sentinel in both fields and keep omitting an untouched redacted value on submit - Consolidate duplicate EIN regexes into a shared helpers/validations EIN_REGEX - Restore the document PDF URL on the hook and surface a download link plus an IRS Form W-9 instructions link (no inline preview) - Regenerate API report and docs Co-authored-by: Cursor <cursoragent@cursor.com>
This was referenced Jul 1, 2026
Member
Author
|
Superseded — decomposed into two stacked PRs for easier review:
Closing this in favor of those. |
3 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Second PR in the contractor-documents series, stacked on #2298 (
Contractor.DocumentsList). Adds theSignatureFormcomponent and theuseContractorSignatureFormheadless hook for signing a contractor document (W-9).fields[]payload (same pattern asuseEmployeeStateTaxesForm). Field labels/descriptions come from SDK i18n, not the API.individual_proprietor,c_corporation, …,limited_liability_company) are synthesized into a single radio group with conditional LLC / "other" sub-fields, then serialized back to the API'skey/valueshape (0/1) on submit.(optional)), and the field is omitted from the sign payload when untouched — so the mask is never written back.Contractor.SignatureFormi18n namespace, scopedCONTRACTOR_SIGN_DOCUMENTevent, and a self-contained component reusingCommon/DocumentViewerfor the PDF preview.The orchestrator (
ContractorDocumentSignerstate machine that composes the list + signature form) will follow in a third PR.Notable changes outside the component
partner-hook-utils/types.ts:FieldMetadatagains an optionalplaceholderso hooks can surface a masked value.src/index.ts/contractorOnboarding.ts: export the hook + component surface.src/test/mocks/apis/contractor_documents.ts: W-9 fixture +get/pdf/signhandlers.Test plan
npm run test -- --run src/components/Contractor— 140 passednpx tsc --noEmitcleaneslintclean on touched filesContractorOnboarding.SignatureFormwithcontractorId+documentUuid); verify redacted SSN shows as placeholder and isn't sent back.Screen.Recording.2026-06-30.at.4.52.45.PM.mov
Made with Cursor