curl --request POST \
--url https://skala-sandbox.ripio.com/api/v1/customers/{customerId}/kyc/start/ \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"redirectUrl": "https://www.example.com/",
"kycProviderShareToken": "<string>"
}
'import requests
url = "https://skala-sandbox.ripio.com/api/v1/customers/{customerId}/kyc/start/"
payload = {
"redirectUrl": "https://www.example.com/",
"kycProviderShareToken": "<string>"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({redirectUrl: 'https://www.example.com/', kycProviderShareToken: '<string>'})
};
fetch('https://skala-sandbox.ripio.com/api/v1/customers/{customerId}/kyc/start/', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://skala-sandbox.ripio.com/api/v1/customers/{customerId}/kyc/start/",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'redirectUrl' => 'https://www.example.com/',
'kycProviderShareToken' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://skala-sandbox.ripio.com/api/v1/customers/{customerId}/kyc/start/"
payload := strings.NewReader("{\n \"redirectUrl\": \"https://www.example.com/\",\n \"kycProviderShareToken\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://skala-sandbox.ripio.com/api/v1/customers/{customerId}/kyc/start/")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"redirectUrl\": \"https://www.example.com/\",\n \"kycProviderShareToken\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://skala-sandbox.ripio.com/api/v1/customers/{customerId}/kyc/start/")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"redirectUrl\": \"https://www.example.com/\",\n \"kycProviderShareToken\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"submissionId": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"createdAt": "2023-11-07T05:31:56Z",
"providerUrl": "<string>",
"otpRequired": true
}Start KYC
Starts a KYC verification for the customer. Takes no identity data — only a required redirectUrl and an optional kycProviderShareToken.
If the customer already has an approved KYC on your account, this returns 400 with the error code 20015 (KycAlreadyApprovedException) — nothing left to do.
Otherwise, an email OTP is sent to the customer as part of starting the verification. The response’s otpRequired tells you what to do next:
otpRequired: true— validate the code with Validate KYC OTP before continuing.otpRequired: false— no OTP step needed. Check the response’sstatusto see what’s next.
If the customer already has an approved KYC with Ripio, validating the OTP approves them immediately — no further steps required. Otherwise, once the OTP is confirmed, submit the customer’s data with Submit KYC Information to complete the verification.
curl --request POST \
--url https://skala-sandbox.ripio.com/api/v1/customers/{customerId}/kyc/start/ \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"redirectUrl": "https://www.example.com/",
"kycProviderShareToken": "<string>"
}
'import requests
url = "https://skala-sandbox.ripio.com/api/v1/customers/{customerId}/kyc/start/"
payload = {
"redirectUrl": "https://www.example.com/",
"kycProviderShareToken": "<string>"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({redirectUrl: 'https://www.example.com/', kycProviderShareToken: '<string>'})
};
fetch('https://skala-sandbox.ripio.com/api/v1/customers/{customerId}/kyc/start/', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://skala-sandbox.ripio.com/api/v1/customers/{customerId}/kyc/start/",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'redirectUrl' => 'https://www.example.com/',
'kycProviderShareToken' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://skala-sandbox.ripio.com/api/v1/customers/{customerId}/kyc/start/"
payload := strings.NewReader("{\n \"redirectUrl\": \"https://www.example.com/\",\n \"kycProviderShareToken\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://skala-sandbox.ripio.com/api/v1/customers/{customerId}/kyc/start/")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"redirectUrl\": \"https://www.example.com/\",\n \"kycProviderShareToken\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://skala-sandbox.ripio.com/api/v1/customers/{customerId}/kyc/start/")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"redirectUrl\": \"https://www.example.com/\",\n \"kycProviderShareToken\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"submissionId": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"createdAt": "2023-11-07T05:31:56Z",
"providerUrl": "<string>",
"otpRequired": true
}kycSubmission — identity data is sent afterwards through Submit KYC Information, once the OTP is confirmed (or skipped entirely, if the response already resolved the identity).400KycAlreadyApprovedException(20015) — this customer already has an approved KYC on your account. No OTP is sent and nothing is opened; skip KYC entirely and continue with the quote.403KycUnifiedFlowNotEnabledException(20095) — the unified KYC flow is not enabled for this account. This endpoint (and Resend KYC OTP / Validate KYC OTP) only works for accounts that run KYC through the API integration, authenticated with the API credentials. The most common cause is calling it with the widget credentials instead — the unified flow is only enabled for the API keys, not for the widget session credentials. Switch to the API credentials; if you already are, send the key ID (not the secret) to Ripio and we’ll check the account configuration.otpRequired: true— validate the code with Validate KYC OTP before doing anything else. If the customer already has an approved KYC with Ripio, that validation approves them immediately — no data required.otpRequired: false— no OTP left to validate. Check the response’sstatus: continue with Submit KYC Information if data is still missing, or move on to polling otherwise.
Authorizations
Access token obtained via /oauth2/token/. Use as Authorization: Bearer <access_token>.
Path Parameters
Unique identifier for the customer.
Body
Request body to start a KYC verification. Takes no identity data.
URL to redirect the user to after completing the KYC flow.
"https://www.example.com/"
Optional. Sumsub share token for a customer already verified in your own Sumsub account (Reusable KYC) — see kycProviderShareToken on Submit KYC Information for the full behavior and prerequisites; it works the same way here.
2000Response
KYC verification started.
Unique identifier for the submitted KYC data.
Date and time the KYC submission was created (UTC format).
Points to a third-party KYC provider's widget to handle file uploads and liveness checks. Only available in production.
Whether the OTP sent to the customer's email still needs to be validated with Validate KYC OTP before continuing. Only present for accounts configured for Ripio KYC reuse via OTP.
Was this page helpful?