KYC & Accreditation
User verification flows for Know Your Customer and accredited investor checks.
Users must complete KYC (Know Your Customer) verification before subscribing to offerings. Both KYC and accredited investor verification are API-driven: your backend submits the user's PII or accreditation claim to Identity, uploads any supporting documents directly to S3 via presigned URLs, and polls or subscribes to webhooks for the result.
KYC endpoints require a Rialto access_token and use the token's org_id claim for organization scoping. Accreditation endpoints also require a Rialto access_token (obtained via token exchange).
KYC Flow
How It Works
- Your backend submits the user's KYC PII to Identity
- Identity upserts
user_piiand creates a KYC verification - Rialto sends the check to its verification provider
- If a document scan is required, the response includes a provider URL in
required_action.url - You are notified via webhook or poll for the result
Creating a KYC Verification
curl -X POST https://api.rialto.com/identity/kyc-verifications \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <rialto_access_token>" \
-d '{
"firstName": "JOHN",
"lastName": "SMITH",
"address": "222333 PEACHTREE PLACE",
"city": "ATLANTA",
"state": "GA",
"zip": "30318",
"country": "USA",
"ssn": "112223333",
"dobMonth": "02",
"dobDay": "28",
"dobYear": "1975",
"email": "john.smith@example.com",
"telephone": "4045551212",
"idType": "driverLicense",
"idIssuer": "GA",
"idNumber": "0123456789"
}'Use either a 9-digit ssn or a 4-digit ssnLast4; do not include dashes or spaces.
Response (201):
{
"success": true,
"data": {
"verification_id": "a1b2c3d4-...",
"user_id": "70000000-...",
"org_id": "550e8400-...",
"status": "action_required",
"checks": {
"identity": "needs_review",
"document": "pending"
},
"required_action": {
"type": "document_scan",
"url": "https://..."
},
"submitted_at": "2026-03-15T10:30:00.000Z",
"completed_at": null,
"created_at": "2026-03-15T10:30:00.000Z",
"updated_at": "2026-03-15T10:30:00.000Z"
}
}KYC responses are vendor-neutral. They do not expose raw provider payloads, provider status codes, reason flags, ID/selfie artifacts, or provider-specific field names.
KYC Verification Statuses
| Status | Description | Terminal? |
|---|---|---|
not_started | User has no KYC verification yet | No |
pending | Identity check is in progress | No |
action_required | User must complete an action, such as document scan | No |
needs_review | Needs manual review by Rialto staff | No |
approved | Identity verified successfully | Yes |
rejected | Identity verification failed or was rejected | Yes |
expired | Verification timed out | Yes |
error | Unrecoverable processing error | Yes |
Check Statuses
Each verification has checks.identity and checks.document fields:
| Check Status | Meaning |
|---|---|
not_attempted | Check not yet run |
pending | Check in progress |
passed | Check passed |
failed | Check failed |
needs_review | Could not verify automatically |
Checking KYC Status
# Get a specific verification
curl https://api.rialto.com/identity/kyc-verifications/<verification_id> \
-H "Authorization: Bearer <rialto_access_token>"
# Get the latest effective KYC status for the authenticated user
curl https://api.rialto.com/identity/kyc \
-H "Authorization: Bearer <rialto_access_token>"
# org_admin only: list sanitized KYC verifications in your organization
curl https://api.rialto.com/identity/kyc-verifications \
-H "Authorization: Bearer <rialto_access_token>"KYC Webhook Events
Subscribe to these events via the webhooks API:
| Event | When it fires |
|---|---|
kyc.verification.created | Verification created |
kyc.verification.action_required | User must complete a required action |
kyc.verification.needs_review | Flagged for manual review |
kyc.verification.approved | Verification passed |
kyc.verification.rejected | Verification failed |
Accreditation Flow
Accreditation is a single record per user/org — there are no sessions. The same record is updated through self-certification and (when required) document review.
How It Works
- Your backend fetches or initializes the user's accreditation record
- The user self-certifies an
accreditationStatusandaccreditationBasis - If the basis requires proof, your backend requests a presigned S3 upload URL
- Your client PUTs the file directly to S3, then finalizes the upload with Rialto
- Rialto queues the accreditation for admin review
- You are notified via webhook or poll for the result
Getting the Current Accreditation
GET /identity/accreditations returns the user's current record (creating a baseline pending record on first call).
curl https://api.rialto.com/identity/accreditations \
-H "Authorization: Bearer <rialto_access_token>"Submitting Self-Certification
PUT /identity/accreditations upserts the user's self-certified accreditation.
curl -X PUT https://api.rialto.com/identity/accreditations \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <rialto_access_token>" \
-d '{
"accreditationStatus": "accredited",
"accreditationBasis": "income"
}'| Field | Values |
|---|---|
accreditationStatus | accredited, non_accredited |
accreditationBasis | income, net_worth, license_7_65_82, entity, not_accredited |
Non-accredited self-certification finalizes immediately. Accredited self-certification with a basis that requires proof transitions the review status to pending_review and waits for a document upload.
Review Statuses
The accreditation record's review_status drives the lifecycle:
| Review Status | Description | Terminal? |
|---|---|---|
not_required | No admin review needed (e.g., self-certified non-accredited) | No |
pending_review | Awaiting document upload or admin pickup | No |
under_review | Admin is reviewing | No |
more_info_needed | Admin requested additional information | No |
approved | Accreditation verified by admin | Yes |
denied | Accreditation denied by admin | Yes |
expired | Accreditation lapsed | Yes |
Accreditation Statuses
The user's effective accreditation classification:
| Status | Description |
|---|---|
pending | Not yet self-certified |
accredited | Accredited investor |
non_accredited | Not accredited |
qualified_purchaser | Qualified purchaser (QP) |
qualified_client | Qualified client (QC) |
expired | Accreditation expired |
Accreditation Bases
The basis for accreditation:
| Basis | Description |
|---|---|
income | Income-based accreditation |
net_worth | Net worth-based |
license_7_65_82 | Series 7, 65, or 82 license holder |
entity | Entity-based accreditation |
not_accredited | Not accredited |
Uploading Supporting Documents
Document upload is a two-step process. First, request a presigned S3 PUT URL:
curl -X POST https://api.rialto.com/identity/accreditations/documents \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <rialto_access_token>" \
-d '{
"documentType": "income_proof",
"fileName": "tax-return-2025.pdf",
"contentType": "application/pdf",
"fileSizeBytes": 524288
}'| Field | Required | Description |
|---|---|---|
documentType | Yes | income_proof, net_worth_proof, license_proof, or entity_proof (must match the submitted basis) |
fileName | Yes | Original file name |
contentType | Yes | application/pdf, image/jpeg, or image/png |
fileSizeBytes | Yes | File size in bytes (max 10 MB) |
Response (201):
{
"success": true,
"data": {
"id": "d4e5f6a7-...",
"accreditation_id": "b2c3d4e5-...",
"document_type": "income_proof",
"status": "upload_pending",
"upload": {
"method": "PUT",
"url": "https://...presigned...",
"headers": { "Content-Type": "application/pdf" },
"expires_at": "2026-03-15T10:45:00.000Z"
}
}
}Use the returned upload.url to PUT the file directly to S3 from the browser or your backend. Once the file is uploaded, finalize:
curl -X POST https://api.rialto.com/identity/accreditations/documents/<document_id>/upload \
-H "Authorization: Bearer <rialto_access_token>"Finalize HEAD-checks the object in S3 and transitions the document to uploaded. Once a required document is uploaded, the accreditation's review_status becomes pending_review and is queued for admin review.
Document Statuses
| Status | Description |
|---|---|
upload_pending | Presigned URL issued, file not yet confirmed |
uploaded | File present in S3 and verified |
upload_failed | Object missing or exceeds 10 MB on finalize |
Accreditation Webhook Events
| Event | When it fires |
|---|---|
accreditation.submitted | User submitted (self-certified) |
accreditation.document.uploaded | A supporting document was uploaded |
accreditation.more_info_needed | Admin requested more info |
accreditation.approved | Accreditation approved |
accreditation.denied | Accreditation denied |
Token Claims After Verification
After KYC and accreditation are completed, subsequent Rialto tokens include updated claims:
| Event | Claim updated |
|---|---|
| KYC approved | kyc_completed = true |
| Accreditation approved | accredited = true, accreditation_verified = true |
Use these claims for UI hints. Primary Issuance still performs live org-scoped eligibility checks with Identity before subscription create/sign/approval.
Typical User Journey
1. Token Exchange → User gets Rialto access token
2. Create KYC Verification → User verifies identity
3. KYC Approved → live eligibility returns kyc_status = approved
4. Submit Accreditation → User self-certifies (and uploads docs if required)
5. Accreditation Approved → accredited = true in token
6. User can now subscribe to offerings