Skip to main content

Migration Guide: KYB Cases

This release of @zyphe-sdk/core and @zyphe-sdk/node moves KYB management from the KYB result to the KYB case, adds Transaction Monitoring helpers, and updates the bundled OpenAPI types.

If you review KYB in the dashboard, see the KYB dashboard migration guide for what changed there.

Nothing stops working when you upgrade: the previous KYB helpers are deprecated, not removed, and their endpoints still answer. You only have to act if you use the KYB helpers or read the types listed under Type changes.

PackageFromTo
@zyphe-sdk/core0.5.xnext minor (0.6.0)
@zyphe-sdk/node0.4.xnext minor (0.5.0)
@zyphe-sdk/browser0.4.xpatch, no action

Who needs to migrate​

  • You call addKybUbos, removeKybUbo, addKybDirectors, removeKybDirector, requestKybOnDemandDocument, or sendKybUboReminder: move to the case helpers (step 2). Your editor already flags them as deprecated after the upgrade.
  • You approve or reject KYB results from your backend: use decideKybCase (step 4).
  • You import types from @zyphe-sdk/core/openapi: check Type changes.
  • You only create verification sessions, verify webhooks, or use the Export API: upgrade, no code change.

1. Upgrade the packages​

pnpm add @zyphe-sdk/node@latest
# or, if you use it directly
pnpm add @zyphe-sdk/core@latest

2. Move to the case helpers​

The case helpers take a caseId instead of a kybResultId. It is the same value: the ID of a KYB result is the ID of its case. Rename the parameter and keep passing the ID you already store.

DeprecatedReplacement
addKybUbosaddKybCaseUbos
removeKybUboremoveKybCaseUbo
addKybDirectorsaddKybCaseDirectors
removeKybDirectorremoveKybCaseDirector
requestKybOnDemandDocumentrequestKybCaseOnDemandDocument
sendKybUboRemindersendKybCaseUboReminder

Before:

import { addKybUbos } from '@zyphe-sdk/node'

const { data } = await addKybUbos({ organizationId, kybResultId, isSandbox: true, persons }, opts)
const ubos = data?.uboDefinitions ?? []

After:

import { addKybCaseUbos } from '@zyphe-sdk/node'

const { data } = await addKybCaseUbos({ organizationId, caseId: kybResultId, isSandbox: true, persons }, opts)
const ubos = data?.ubos ?? []

The persons payload is unchanged.

3. Read the new officer response​

The four officer helpers (addKybCaseUbos, removeKybCaseUbo, addKybCaseDirectors, removeKybCaseDirector) no longer answer with the whole KYB result. They answer with the case's officers as they stand after the change:

{ caseId: string, ubos: UboDefinition[], directors: DirectorDefinition[] }
Before (KYB result)After (officers)
data.uboDefinitionsdata.ubos
data.directorDefinitionsdata.directors
any other KYB result fieldgetKybCase or getFlowResult

Each person keeps the same stable id, which removeKybCaseUbo / removeKybCaseDirector take as personId. To read the officers without changing them, call getKybCaseOfficers.

The other two replacements behave as before, with two details worth checking:

  • sendKybCaseUboReminder still takes a recipientIndex: the position of the UBO in ubos. Only a UBO with an email can be invited; one declared without an email is rejected.
  • requestKybCaseOnDemandDocument also accepts optional recipientEmail, subject, body, and description next to documentKey. The documentKey must name a document the flow marks as on demand; a document the flow requires upfront is rejected.

4. Decide cases with decideKybCase​

Approving or rejecting a KYB result from your backend now goes through the case decision:

import { decideKybCase } from '@zyphe-sdk/node'

const { data, response } = await decideKybCase(
{
organizationId,
caseId,
isSandbox: true,
outcome: 'REJECTED', // or 'APPROVED'
reason: 'Ownership could not be verified', // mandatory on a rejection
reasonCode: 'CDD_INCOMPLETE', // optional classification
},
opts,
)
  • The POST /sdk/organizations/{organization_id}/kyb/{kyb_result_id}/approve and /reject endpoints are deprecated in favour of this one. Send outcome: 'APPROVED' or outcome: 'REJECTED'; reason, reasonCode, and dueDiligenceLevel carry over.
  • The answer is the decision (outcome, statusBefore, statusAfter, decisionId), not the KYB result. Read the case with getKybCase afterwards if you need it.
  • Handle 202: when the organization's approval matrix requires two signatures, the call records a decisionProposal instead of closing the case. The second signature must come from a person in the dashboard: an API key can propose a decision but cannot confirm one. See Decide a case.
  • A decision is final. A decided case cannot be decided again.

5. Handle the new error tags​

Refusals of a case decision now carry their own errorTag, so you can tell the user why instead of showing a generic bad request:

errorTagMeaning
kyb_case_not_decidableThe case's status does not accept this decision (for example, it is already decided)
kyb_case_not_readyThe case is not ready for review yet: an approval needs it in READY_FOR_REVIEW
kyb_case_exception_requiredThe approval rests on something that needs a recorded exception first; the message lists what
kyb_case_rejecting_hitA confirmed screening match stands on the case and the organization's policy rejects it
kyb_case_reason_requiredThe decision needs a reason (every rejection, and an approval resting on an exception or a match)
kyb_case_decision_not_authorizedThe organization's approval matrix does not let this caller take this decision
kyb_case_second_signature_requiredThe confirmation of a proposal is not valid: it must come from a person other than the proposer

All of them are 400. The message names the specific blocker, so log it.

Type changes​

These only affect code that reads the generated types exported from @zyphe-sdk/core/openapi (components['schemas'][...]):

  • KybConfig no longer has articlesOfAssociation, certificateOfIncorporation, customDocuments, organizationalStructureChart, or proofOfAttorney. KYB documents are configured on the KYB_DOCUMENTS step (KybDocumentsConfig); see KYB steps and configuration.
  • FlowStepType gains KYB_DOCUMENTS, KYB_UBOS, and KYB_DIRECTORS. Update exhaustive switch statements over step types.
  • Flow no longer has webhookUrl. Webhook destinations are configured as webhook endpoints.
  • ErrorTags no longer contains websocket.
  • Removed schemas that were not used by any SDK helper: CustomDocumentConfig, DocumentConfig, ModerateKybResultPayload, ModerateKybResultResponse, PagedCommunicationsResponse, PagedDocumentRequestsResponse, Uuid, and the dashboard List*Response types.

Additive changes need no action: new optional fields such as SdkCreateVerificationRequestResponse.sessionId, KybMetadata.dueDiligenceLevel, and DvConfig.capture, plus the new KYB case and Transaction Monitoring schemas.

Checklist​

  • Upgrade @zyphe-sdk/node (and @zyphe-sdk/core if you depend on it directly).
  • Replace the six deprecated KYB helpers and rename kybResultId to caseId.
  • Read ubos / directors instead of uboDefinitions / directorDefinitions.
  • Move backend approvals and rejections to decideKybCase, handling 202.
  • Map the new kyb_case_* error tags to user-facing messages.
  • Fix compile errors from the type changes, if any.
  • Run the flow end to end in the sandbox before switching production keys.