Description
Cross-border payment flows mediated by SEP-31 anchors require counterparties to complete KYC via the SEP-12 PUT /customer endpoint before a transfer can proceed. The SDK currently leaves callers to construct and submit these requests manually with no field validation or structured error handling. A SEP-12 handler would abstract the upload of KYC text fields and binary documents, poll for approval status, and surface a typed KycNeedsInfoError when the anchor rejects or requests additional fields.
Technical Context
New module src/sep/sep12.ts with a Sep12Client class. Derives the KYC_SERVER URL from the anchor's TOML file using existing TOML utilities in src/utils/toml.ts. Interfaces KycFields, KycDocument, KycStatus, and KycNeedsInfoError added to src/types.ts. Uses FormData and fetch for multipart document upload. The existing SEP-10 auth interceptor in src/auth/sep10.ts is reused to attach the bearer token automatically.
Acceptance Criteria
Description
Cross-border payment flows mediated by SEP-31 anchors require counterparties to complete KYC via the SEP-12
PUT /customerendpoint before a transfer can proceed. The SDK currently leaves callers to construct and submit these requests manually with no field validation or structured error handling. A SEP-12 handler would abstract the upload of KYC text fields and binary documents, poll for approval status, and surface a typedKycNeedsInfoErrorwhen the anchor rejects or requests additional fields.Technical Context
New module
src/sep/sep12.tswith aSep12Clientclass. Derives theKYC_SERVERURL from the anchor's TOML file using existing TOML utilities insrc/utils/toml.ts. InterfacesKycFields,KycDocument,KycStatus, andKycNeedsInfoErroradded tosrc/types.ts. UsesFormDataandfetchfor multipart document upload. The existing SEP-10 auth interceptor insrc/auth/sep10.tsis reused to attach the bearer token automatically.Acceptance Criteria
Sep12Client.putCustomer(fields: KycFields, docs?: KycDocument[])submits text fields and optional binary attachments in a singlemultipart/form-dataPUT requestSep12Client.getCustomer(id: string): Promise<KycStatus>returns a typed status object with discriminated unionACCEPTED | PROCESSING | NEEDS_INFO | REJECTEDNEEDS_INFO, the resolved value includes amissingFields: string[]list derived from the anchor's response bodyAuthorization: Bearer <token>without callers having to pass it manuallyNEEDS_INFOandREJECTEDerror paths