curl --request POST \
--url https://api.rolla.xyz/api/v1/external/accounts/{accountId}/verification \
--header 'Content-Type: multipart/form-data' \
--header 'X-API-Key: <api-key>' \
--form document=@example-file \
--form documentBack=@example-file \
--form documentType=ID_CARD \
--form country=NG \
--form front=@example-file \
--form back=@example-fileimport requests
url = "https://api.rolla.xyz/api/v1/external/accounts/{accountId}/verification"
files = {
"document": ("example-file", open("example-file", "rb")),
"documentBack": ("example-file", open("example-file", "rb")),
"front": ("example-file", open("example-file", "rb")),
"back": ("example-file", open("example-file", "rb"))
}
payload = {
"documentType": "ID_CARD",
"country": "NG"
}
headers = {"X-API-Key": "<api-key>"}
response = requests.post(url, data=payload, files=files, headers=headers)
print(response.text)const form = new FormData();
form.append('document', '<string>');
form.append('documentBack', '<string>');
form.append('documentType', 'ID_CARD');
form.append('country', 'NG');
form.append('front', '<string>');
form.append('back', '<string>');
const options = {method: 'POST', headers: {'X-API-Key': '<api-key>'}};
options.body = form;
fetch('https://api.rolla.xyz/api/v1/external/accounts/{accountId}/verification', 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://api.rolla.xyz/api/v1/external/accounts/{accountId}/verification",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => "-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"document\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"documentBack\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"documentType\"\r\n\r\nID_CARD\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"country\"\r\n\r\nNG\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"front\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"back\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n<string>\r\n-----011000010111000001101001--",
CURLOPT_HTTPHEADER => [
"Content-Type: multipart/form-data",
"X-API-Key: <api-key>"
],
]);
$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://api.rolla.xyz/api/v1/external/accounts/{accountId}/verification"
payload := strings.NewReader("-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"document\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"documentBack\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"documentType\"\r\n\r\nID_CARD\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"country\"\r\n\r\nNG\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"front\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"back\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n<string>\r\n-----011000010111000001101001--")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("X-API-Key", "<api-key>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.rolla.xyz/api/v1/external/accounts/{accountId}/verification")
.header("X-API-Key", "<api-key>")
.body("-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"document\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"documentBack\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"documentType\"\r\n\r\nID_CARD\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"country\"\r\n\r\nNG\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"front\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"back\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n<string>\r\n-----011000010111000001101001--")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.rolla.xyz/api/v1/external/accounts/{accountId}/verification")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["X-API-Key"] = '<api-key>'
request.body = "-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"document\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"documentBack\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"documentType\"\r\n\r\nID_CARD\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"country\"\r\n\r\nNG\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"front\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"back\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n<string>\r\n-----011000010111000001101001--"
response = http.request(request)
puts response.read_body{
"status": 201,
"message": "Verification token created successfully",
"success": true,
"data": {
"sumsubToken": {
"token": "_act-sbx-jwt-eyJhbGciOiJub25lIn0...",
"userId": "b6075be0-f1d0-451f-a468-3e94563101d2"
},
"externalUserId": "b6075be0-f1d0-451f-a468-3e94563101d2"
}
}{
"status": 400,
"message": "Validation failed",
"code": "ACCOUNT_RESTRICTED",
"errors": [
{
"path": [
"amount"
],
"message": "amount must be a whole number of smallest currency units (e.g. cents)"
}
]
}{
"status": 400,
"message": "Validation failed",
"code": "ACCOUNT_RESTRICTED",
"errors": [
{
"path": [
"amount"
],
"message": "amount must be a whole number of smallest currency units (e.g. cents)"
}
]
}{
"status": 400,
"message": "Validation failed",
"code": "ACCOUNT_RESTRICTED",
"errors": [
{
"path": [
"amount"
],
"message": "amount must be a whole number of smallest currency units (e.g. cents)"
}
]
}Create Verification Token
Uploads the account holder’s identity document and returns a Sumsub WebSDK access token for the liveness check, in one call. For an individual account only.
The document is required. The SDK session covers liveness only, so a token issued without a document leaves the applicant with no identity document on file, and USD account issuance then fails because the document set is incomplete.
Tokens expire after 30 minutes; call this again for a new one. For business accounts, use the related-person KYC link instead.
curl --request POST \
--url https://api.rolla.xyz/api/v1/external/accounts/{accountId}/verification \
--header 'Content-Type: multipart/form-data' \
--header 'X-API-Key: <api-key>' \
--form document=@example-file \
--form documentBack=@example-file \
--form documentType=ID_CARD \
--form country=NG \
--form front=@example-file \
--form back=@example-fileimport requests
url = "https://api.rolla.xyz/api/v1/external/accounts/{accountId}/verification"
files = {
"document": ("example-file", open("example-file", "rb")),
"documentBack": ("example-file", open("example-file", "rb")),
"front": ("example-file", open("example-file", "rb")),
"back": ("example-file", open("example-file", "rb"))
}
payload = {
"documentType": "ID_CARD",
"country": "NG"
}
headers = {"X-API-Key": "<api-key>"}
response = requests.post(url, data=payload, files=files, headers=headers)
print(response.text)const form = new FormData();
form.append('document', '<string>');
form.append('documentBack', '<string>');
form.append('documentType', 'ID_CARD');
form.append('country', 'NG');
form.append('front', '<string>');
form.append('back', '<string>');
const options = {method: 'POST', headers: {'X-API-Key': '<api-key>'}};
options.body = form;
fetch('https://api.rolla.xyz/api/v1/external/accounts/{accountId}/verification', 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://api.rolla.xyz/api/v1/external/accounts/{accountId}/verification",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => "-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"document\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"documentBack\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"documentType\"\r\n\r\nID_CARD\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"country\"\r\n\r\nNG\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"front\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"back\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n<string>\r\n-----011000010111000001101001--",
CURLOPT_HTTPHEADER => [
"Content-Type: multipart/form-data",
"X-API-Key: <api-key>"
],
]);
$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://api.rolla.xyz/api/v1/external/accounts/{accountId}/verification"
payload := strings.NewReader("-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"document\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"documentBack\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"documentType\"\r\n\r\nID_CARD\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"country\"\r\n\r\nNG\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"front\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"back\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n<string>\r\n-----011000010111000001101001--")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("X-API-Key", "<api-key>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.rolla.xyz/api/v1/external/accounts/{accountId}/verification")
.header("X-API-Key", "<api-key>")
.body("-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"document\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"documentBack\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"documentType\"\r\n\r\nID_CARD\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"country\"\r\n\r\nNG\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"front\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"back\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n<string>\r\n-----011000010111000001101001--")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.rolla.xyz/api/v1/external/accounts/{accountId}/verification")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["X-API-Key"] = '<api-key>'
request.body = "-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"document\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"documentBack\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"documentType\"\r\n\r\nID_CARD\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"country\"\r\n\r\nNG\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"front\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n<string>\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"back\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n<string>\r\n-----011000010111000001101001--"
response = http.request(request)
puts response.read_body{
"status": 201,
"message": "Verification token created successfully",
"success": true,
"data": {
"sumsubToken": {
"token": "_act-sbx-jwt-eyJhbGciOiJub25lIn0...",
"userId": "b6075be0-f1d0-451f-a468-3e94563101d2"
},
"externalUserId": "b6075be0-f1d0-451f-a468-3e94563101d2"
}
}{
"status": 400,
"message": "Validation failed",
"code": "ACCOUNT_RESTRICTED",
"errors": [
{
"path": [
"amount"
],
"message": "amount must be a whole number of smallest currency units (e.g. cents)"
}
]
}{
"status": 400,
"message": "Validation failed",
"code": "ACCOUNT_RESTRICTED",
"errors": [
{
"path": [
"amount"
],
"message": "amount must be a whole number of smallest currency units (e.g. cents)"
}
]
}{
"status": 400,
"message": "Validation failed",
"code": "ACCOUNT_RESTRICTED",
"errors": [
{
"path": [
"amount"
],
"message": "amount must be a whole number of smallest currency units (e.g. cents)"
}
]
}Document types
documentType | Reverse side |
|---|---|
INTERNATIONAL_PASSPORT (default) | not needed |
ID_CARD | required |
DRIVER_LICENSE | required |
RESIDENCE_PERMIT | required |
documentBack. Omitting it for one of the two-sided types is rejected with a message naming the field.
country is the 2-letter ISO code of the issuing country. Leave it out and the country on the account’s address is used.
Example Request
curl -X POST "https://api.rolla.xyz/api/v1/external/accounts/b6075be0-f1d0-451f-a468-3e94563101d2/verification" \
-H "X-API-Key: your_api_key_here" \
-F "documentType=INTERNATIONAL_PASSPORT" \
-F "country=NG" \
-F "document=@passport.jpg"
curl -X POST "https://api.rolla.xyz/api/v1/external/accounts/b6075be0-f1d0-451f-a468-3e94563101d2/verification" \
-H "X-API-Key: your_api_key_here" \
-F "documentType=ID_CARD" \
-F "country=NG" \
-F "document=@id-front.jpg" \
-F "documentBack=@id-back.jpg"
Example Response
{
"status": 201,
"message": "Verification token created successfully",
"success": true,
"data": {
"sumsubToken": {
"token": "_act-sbx-jwt-eyJhbGciOiJub25lIn0...",
"userId": "b6075be0-f1d0-451f-a468-3e94563101d2"
},
"externalUserId": "b6075be0-f1d0-451f-a468-3e94563101d2"
}
}
Using the token
Pass the token to the Sumsub WebSDK in your frontend. The document is already on file by this point, so the session the user sees is the liveness check:import SumsubWebSdk from '@sumsub/websdk-react';
<SumsubWebSdk
accessToken={data.sumsubToken.token}
expirationHandler={() => fetchNewToken()}
/>
Authorizations
Your Rolla API key
Path Parameters
Identifier of an account owned by the same user as your API key's business
Body
The account holder's identity document, image or PDF. Front side for a two-sided document
Reverse side. Required for ID_CARD, DRIVER_LICENSE and RESIDENCE_PERMIT
Which identity document is being sent. Defaults to INTERNATIONAL_PASSPORT
INTERNATIONAL_PASSPORT, ID_CARD, DRIVER_LICENSE, RESIDENCE_PERMIT "ID_CARD"
2-letter ISO code of the country that issued the document. Defaults to the country on the account's address
2"NG"
Alias for document
Alias for documentBack