SettleMint
Compliance

KYC version submission

Create, edit, submit, and read back a versioned KYC profile, including the review-outcome trail, through the DALP Platform API, SDK, and CLI.

KYC data on DALP is versioned. A user's identity submission lives in a KYC profile version that moves through a fixed lifecycle: you create a draft, edit it, attach documents, and submit it for review. Submission locks the version and hands it to a reviewer, who approves it, rejects it, or requests changes.

Each step is a single Platform API call against the user or version ID: read the profile, list versions, create a draft, read or update a draft, and submit it. The reviewer decisions that follow submission live in KYC reviewer version actions. The operator walkthrough in the Console lives in Provide KYC data.

Version lifecycle

A version holds one status at a time, and each status allows a fixed set of operations. The happy path runs in order: create a draft, edit it, attach documents, then submit.

StatusWhat it meansWhat you can do
draftThe version is being prepared.Edit fields, attach or remove documents, and submit.
under_reviewThe version is in the review workflow.Read the submission. Editing is locked until review ends.
approvedA reviewer accepted the version.Read the approved data. Create a new draft to make changes.
rejectedA reviewer declined the version.Read the rejection reason and create a corrected draft.

A user keeps at most one open draft. A single-version read returns canEdit, canSubmit, and canReview flags so your integration can drive the interface from the platform's view of the current state instead of inferring it. The profile read reports the user's overall position one level up, through the computed status field described below.

Read the profile

Read the profile to find the user's overall KYC standing, approved version, latest version, and whether an update is pending. Start here when you build a KYC screen for a user or decide whether a participant may proceed with a KYC-gated operation.

const profile = await client.user.kyc.profile.read({
  params: { userId: "usr_01hzt7n4investor0001" },
});

Direct HTTP integrations call GET /api/v2/kyc-profiles/{userId}.

The status field is the profile's computed standing across its version history. Read it to decide whether a participant has cleared KYC without walking the version list yourself.

StatusWhat it means
incompleteThe user has only a draft, or no version at all.
submittedA version has been submitted and is awaiting review.
under_reviewA version is actively being reviewed.
approvedAn approved version is in effect; the user has cleared KYC.
rejectedThe latest version was rejected.
update_requiredA reviewer requested changes; the user must resubmit.

Alongside status, the response carries hasPendingUpdate, the approvedVersion pointer, the latestVersion pointer, an openActionRequestsCount, and the profile's createdAt and updatedAt timestamps. The approvedVersion and latestVersion objects are null until the user has a version in that state.

{
  "data": {
    "id": "kyc_01hzt7n4profile00001",
    "userId": "usr_01hzt7n4investor0001",
    "status": "approved",
    "hasPendingUpdate": false,
    "approvedVersion": {
      "id": "kycv_01hzt7n4approvedversion",
      "versionNumber": 2,
      "firstName": "Maria",
      "lastName": "Santos",
      "contentHash": null,
      "approvedAt": "2026-05-24T11:02:47.880Z",
      "approvedBy": "usr_01hzt7n4reviewer0001"
    },
    "latestVersion": {
      "id": "kycv_01hzt7n4approvedversion",
      "versionNumber": 2,
      "status": "approved",
      "isDraft": false,
      "createdAt": "2026-05-24T09:58:11.204Z"
    },
    "openActionRequestsCount": 0,
    "createdAt": "2026-05-24T09:45:33.112Z",
    "updatedAt": "2026-05-24T11:02:47.880Z"
  },
  "links": {
    "self": "/api/v2/kyc-profiles/usr_01hzt7n4investor0001"
  }
}

List versions

List a user's versions to show their submission history. The list filters by status, paginates, and reports which version is approved and which is current, so a review queue can show one user's submissions without extra calls.

const versions = await client.user.kyc.versions.list({
  params: { userId: "usr_01hzt7n4investor0001" },
  query: { status: { inArray: "under_review,approved" }, limit: 10 },
});

Direct HTTP integrations call GET /api/v2/kyc-profiles/{userId}/versions. The endpoint uses the collection envelope: data holds the page of versions, meta reports the total count and facet breakdowns, and links carries pagination links.

The response sorts by versionNumber ascending by default and supports sorting and filtering on versionNumber, status, createdAt, submittedAt, and reviewedAt. Page through results with page[offset] and page[limit].

Each version row includes isDraft, isUnderReview, isApproved, and isCurrent flags, so an interface can label the draft in progress, the submission under review, and the approved version currently in effect without recomputing status.

The meta.facets block reports a count for each status value across the current filtered set, so a review queue can show how many versions sit in each status without a second call. The counts reflect the active filters.

Create a draft

Create a draft to start a new submission. A draft clones its starting values from the user's approved version by default, or from the latest version. When a user has no version yet, supply the starting values through initialData.

const draft = await client.user.kyc.versions.create({
  params: { userId: "usr_01hzt7n4investor0001" },
  body: {
    cloneFrom: "approved",
    initialData: {
      firstName: "Maria",
      lastName: "Santos",
      country: "PT",
    },
  },
});

Direct HTTP integrations call POST /api/v2/kyc-profiles/{userId}/versions. The initialData object carries the identity fields the user supplies. A date of birth, when provided, must place the user at age 18 or older. The new draft returns with status set to draft and the next versionNumber.

{
  "data": {
    "id": "kycv_01hzt7n4newdraft0001",
    "versionNumber": 2,
    "status": "draft",
    "userId": "usr_01hzt7n4investor0001",
    "createdAt": "2026-05-24T09:58:11.204Z",
    "createdBy": "usr_01hzt7n4investor0001"
  }
}

After the draft exists, attach supporting files with the KYC document uploads API. Documents can be added or removed only while the version stays in draft.

Update a draft

Update a draft to correct identity fields before submission. Only a draft version accepts edits. Once a version leaves draft, create a new draft to make further changes.

const updated = await client.user.kyc.version.update({
  params: { versionId: "kycv_01hzt7n4newdraft0001" },
  body: {
    residencyStatus: "resident",
  },
});

Direct HTTP integrations call PATCH /api/v2/kyc-profile-versions/{versionId}.

Read a version

Read a single version to show its full state and workflow metadata. The response carries the identity fields, the version status, the attached documentsCount, and the canEdit, canSubmit, and canReview flags so your integration can drive the interface from the platform's view of the current state.

const version = await client.user.kyc.version.read({
  params: { versionId: "kycv_01hzt7n4newdraft0001" },
});

Direct HTTP integrations call GET /api/v2/kyc-profile-versions/{versionId}.

Read back the review trail

The same response shows who acted on the version at each stage, so an audit or review-queue integration can read back a finished decision without inferring it. The platform fills these fields in as the version moves through the workflow:

FieldWhen the platform sets itWhat it holds
createdByOn draft creationThe user who created the draft version.
submittedAtOn submissionThe time the version entered review.
submittedByOn submissionThe user who submitted the version for review.
reviewedAtOn a reviewer decisionThe time a reviewer approved, rejected, or requested changes.
reviewedByOn the same decisionThe reviewer who made the call.
reviewOutcomeOn the same decisionThe outcome: approved, rejected, or changes_requested.
reviewNotesOn a reviewer decisionThe note or reason saved alongside the outcome. For changes_requested, the platform stores the required reason here when the reviewer does not add an explicit note.
rejectionReasonOn a rejectionThe reason given when a reviewer rejects the version.

A field stays null until the version reaches the stage that sets it. A draft has no submission or review fields yet; an approved or rejected version carries the full trail. Read the version after a reviewer acts to confirm the outcome and who signed off.

{
  "data": {
    "id": "kycv_01hzt7n4submittedversion",
    "userId": "usr_01hzt7n4investor0001",
    "versionNumber": 2,
    "status": "approved",
    "submittedAt": "2026-05-24T09:58:11.204Z",
    "submittedBy": "usr_01hzt7n4investor0001",
    "reviewedAt": "2026-05-24T11:02:47.880Z",
    "reviewedBy": "usr_01hzt7n4reviewer0001",
    "reviewOutcome": "approved",
    "reviewNotes": "ID and proof of address verified against the form fields.",
    "rejectionReason": null,
    "documentsCount": 2,
    "canEdit": false,
    "canSubmit": false,
    "canReview": false
  }
}

For the decisions that set these fields, see KYC reviewer version actions. To scan outcomes across every version of a profile, list the versions and sort by reviewedAt; the list returns each version's reviewOutcome and review actor and timestamp, but read a single version when you need its reviewNotes or rejectionReason.

Submit for review

Submit a draft to send it into the review workflow. Submission moves the version to under_review, records who submitted it and when, and locks the version against further edits. Documents are optional at the platform level, though your organization may require specific documents before a reviewer approves the profile.

const submitted = await client.user.kyc.version.submit({
  params: { versionId: "kycv_01hzt7n4newdraft0001" },
});

Direct HTTP integrations call POST /api/v2/kyc-profile-versions/{versionId}/submissions.

{
  "data": {
    "id": "kycv_01hzt7n4newdraft0001",
    "status": "under_review",
    "submittedBy": "usr_01hzt7n4investor0001"
  }
}

After submission, a reviewer acts on the version. See KYC reviewer version actions for the approve, reject, and request-update decisions and their outcomes.

State transitions

StepFromToSide effect
CreatenonedraftA new draft version is created with the next version number.
UpdatedraftdraftIdentity fields on the draft are changed.
Submitdraftunder_reviewThe version is locked and the profile enters review.

CLI equivalents

The DALP CLI exposes the same submitter steps for operator scripts. Reach for it when a back-office job is easier to run outside the SDK:

TaskCLI command
Read profilekyc profile
List versionskyc versions
Create draftkyc version-create
Read versionkyc version-read
Update draftkyc version-update
Submitkyc version-submit

Validation and error handling

KYC submission returns two classes of error, and your retry logic should treat them differently. A terminal error means the request or the version state is wrong, so a blind retry fails the same way. An operational write failure means validation passed but an internal write did not complete. These are marked non-retryable, so do not resend the same call automatically.

Terminal request errors

Treat these as terminal unless the response says otherwise. Fix the request or the version status before you retry, and store the request ID from the API response when you escalate a repeated platform error.

ErrorWhat DALP observedCaller response
DALP-0391Submit targeted a version that is not in draft.No change is made. Only a draft version can be submitted.
DALP-0392Update targeted a version that is not in draft.No change is made. Create a new draft to make further changes.
DALP-0413Create requested a clone but the user has no version to clone from.Provide initialData for a user who is submitting for the first time.
DALP-0416Profile read or create found no KYC profile for the user.Confirm the user ID, or create the first draft to start the profile.
DALP-0418Create referenced a source version that does not exist.Confirm cloneFromVersionId, or provide initialData instead.
DALP-0421Version read targeted an ID that does not match a KYC version.No change is made. Confirm the version ID.

Operational write failures

These return HTTP 500 after the request passed validation: DALP completed the state-transition check, then a database write returned no result. The error envelope marks these as non-retryable, so do not resend the same call automatically. Escalate with the request ID and the version or user ID rather than changing the payload. For an audit trail, each code names the exact write that did not complete, so a failed onboarding step is traceable to a single operation.

ErrorOperationWhat DALP observedCaller response
DALP-0400CreateThe profile container was confirmed, but the locked profile row needed for version creation could not be read back.Escalate with the request ID and the user ID. The profile is unchanged.
DALP-0401CreateThe draft version data was prepared, but the insert that creates the version returned no result.Escalate with the request ID and the user ID. No draft was created.
DALP-0408UpdateThe version was confirmed as a draft and the field changes were prepared, but the update write returned no result.Escalate with the request ID and the version ID. No fields were modified.
DALP-0407Submit or request updateThe state transition was validated, but the write that updates the version record returned no result. This can occur during a submit-for-review or a changes-requested step.Escalate with the request ID and the version ID. The version stays in its current state until the write lands.

On this page