Upload Document
curl --request POST \
--url https://api.rolla.xyz/api/v1/external/accounts/{accountId}/documents \
--header 'Content-Type: multipart/form-data' \
--header 'X-API-Key: <api-key>' \
--form file=@example-file \
--form documentType=certificate_of_incorporationimport requests
url = "https://api.rolla.xyz/api/v1/external/accounts/{accountId}/documents"
files = { "file": ("example-file", open("example-file", "rb")) }
payload = { "documentType": "certificate_of_incorporation" }
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('file', '@/path/to/certificate.pdf');
form.append('documentType', 'certificate_of_incorporation');
const options = {method: 'POST', headers: {'X-API-Key': '<api-key>'}};
options.body = form;
fetch('https://api.rolla.xyz/api/v1/external/accounts/{accountId}/documents', 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}/documents",
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=\"file\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n@/path/to/certificate.pdf\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"documentType\"\r\n\r\ncertificate_of_incorporation\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}/documents"
payload := strings.NewReader("-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"file\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n@/path/to/certificate.pdf\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"documentType\"\r\n\r\ncertificate_of_incorporation\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}/documents")
.header("X-API-Key", "<api-key>")
.body("-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"file\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n@/path/to/certificate.pdf\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"documentType\"\r\n\r\ncertificate_of_incorporation\r\n-----011000010111000001101001--")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.rolla.xyz/api/v1/external/accounts/{accountId}/documents")
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=\"file\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n@/path/to/certificate.pdf\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"documentType\"\r\n\r\ncertificate_of_incorporation\r\n-----011000010111000001101001--"
response = http.request(request)
puts response.read_body{
"status": 201,
"message": "Document uploaded successfully",
"success": true,
"data": {
"id": "0c95b2a1-7a93-4a3a-9a52-2a1f0b9b3c11",
"kyb_application_id": "fbb45236-881a-4c58-8954-22759499eab4",
"document_type": "certificate_of_incorporation",
"file_name": "certificate.pdf",
"file_path": "fbb45236-881a-4c58-8954-22759499eab4/certificate_of_incorporation/certificate_1789655131420.pdf",
"file_size": 248301,
"mime_type": "application/pdf",
"is_required": false,
"uploaded_at": "2026-09-17T14:25:31.420Z"
}
}{
"status": 400,
"message": "No file uploaded. Send the document as multipart/form-data with a \"file\" field."
}{
"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": 404,
"message": "Related person not found"
}Documents
Upload Document
Uploads a document to the account’s application as multipart/form-data. Re-uploading the same documentType replaces the previous file. Use relatedPersonId to attach the document to a specific beneficial owner or director.
POST
/
accounts
/
{accountId}
/
documents
Upload Document
curl --request POST \
--url https://api.rolla.xyz/api/v1/external/accounts/{accountId}/documents \
--header 'Content-Type: multipart/form-data' \
--header 'X-API-Key: <api-key>' \
--form file=@example-file \
--form documentType=certificate_of_incorporationimport requests
url = "https://api.rolla.xyz/api/v1/external/accounts/{accountId}/documents"
files = { "file": ("example-file", open("example-file", "rb")) }
payload = { "documentType": "certificate_of_incorporation" }
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('file', '@/path/to/certificate.pdf');
form.append('documentType', 'certificate_of_incorporation');
const options = {method: 'POST', headers: {'X-API-Key': '<api-key>'}};
options.body = form;
fetch('https://api.rolla.xyz/api/v1/external/accounts/{accountId}/documents', 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}/documents",
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=\"file\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n@/path/to/certificate.pdf\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"documentType\"\r\n\r\ncertificate_of_incorporation\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}/documents"
payload := strings.NewReader("-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"file\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n@/path/to/certificate.pdf\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"documentType\"\r\n\r\ncertificate_of_incorporation\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}/documents")
.header("X-API-Key", "<api-key>")
.body("-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"file\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n@/path/to/certificate.pdf\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"documentType\"\r\n\r\ncertificate_of_incorporation\r\n-----011000010111000001101001--")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.rolla.xyz/api/v1/external/accounts/{accountId}/documents")
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=\"file\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n@/path/to/certificate.pdf\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"documentType\"\r\n\r\ncertificate_of_incorporation\r\n-----011000010111000001101001--"
response = http.request(request)
puts response.read_body{
"status": 201,
"message": "Document uploaded successfully",
"success": true,
"data": {
"id": "0c95b2a1-7a93-4a3a-9a52-2a1f0b9b3c11",
"kyb_application_id": "fbb45236-881a-4c58-8954-22759499eab4",
"document_type": "certificate_of_incorporation",
"file_name": "certificate.pdf",
"file_path": "fbb45236-881a-4c58-8954-22759499eab4/certificate_of_incorporation/certificate_1789655131420.pdf",
"file_size": 248301,
"mime_type": "application/pdf",
"is_required": false,
"uploaded_at": "2026-09-17T14:25:31.420Z"
}
}{
"status": 400,
"message": "No file uploaded. Send the document as multipart/form-data with a \"file\" field."
}{
"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": 404,
"message": "Related person not found"
}Uploads a document to an account’s application as
multipart/form-data. Re-uploading the same documentType replaces the previous file. To attach a document to a specific beneficial owner or director, include their relatedPersonId.
Example Request
curl -X POST "https://api.rolla.xyz/api/v1/external/accounts/eec3cbed-79d8-4370-87a0-b6be9e287337/documents" \
-H "X-API-Key: your_api_key_here" \
-F "file=@/path/to/certificate.pdf" \
-F "documentType=certificate_of_incorporation"
Form Fields
| Field | Type | Required | Description |
|---|---|---|---|
file | file | Yes | The document file (max 50MB) |
documentType | string | Yes | One of the document types below |
relatedPersonId | string | No | Attach the document to a specific related person |
Document Types
Required for business accounts:certificate_of_incorporation, articles_of_association, proof_of_address, director_register, shareholder_register, bank_statement
Required for each beneficial owner and director: proof_of_address, source_of_wealth_doc — upload with that person’s relatedPersonId
Required for individual accounts: proof_of_address
Optional / compliance: proof_of_tax_id, wolfsberg_questionnaire, msb_flow_form, flow_of_funds_diagram, aml_policy_procedures, ach_procedures, wire_procedures, customer_complaint_procedures, prohibited_jurisdictions_industries
Example Response
{
"status": 201,
"message": "Document uploaded successfully",
"success": true,
"data": {
"id": "0c95b2a1-7a93-4a3a-9a52-2a1f0b9b3c11",
"kyb_application_id": "fbb45236-881a-4c58-8954-22759499eab4",
"document_type": "certificate_of_incorporation",
"file_name": "certificate.pdf",
"file_path": "fbb45236-881a-4c58-8954-22759499eab4/certificate_of_incorporation/certificate_1789655131420.pdf",
"file_size": 248301,
"mime_type": "application/pdf",
"is_required": false,
"uploaded_at": "2026-09-17T14:25:31.420Z"
}
}
Response Fields
| Field | Type | Description |
|---|---|---|
id | string | Document identifier |
kyb_application_id | string | The account’s application the document belongs to |
document_type | string | The type the file was uploaded as |
file_name | string | Original file name as uploaded |
file_path | string | Internal storage path, not a download URL. A document attached to a related person carries related-persons/<relatedPersonId> in its path |
file_size | integer | File size in bytes |
mime_type | string | Content type of the uploaded file |
is_required | boolean | Always false for documents uploaded through this API |
uploaded_at | string | When the file was stored |
Errors
| Status | When |
|---|---|
400 | No file part was sent, or documentType is missing or not one of the types above |
404 | Account not found, or relatedPersonId is not a person on this account’s application |
Proof of address documents must have been issued within the last 3 months (bank statement, utility bill or lease agreement).
Authorizations
Your Rolla API key
Path Parameters
Identifier of an account owned by the same user as your API key's business
Body
multipart/form-data
The document file. Maximum 50 MB.
The type this file is being uploaded as
Available options:
certificate_of_incorporation, articles_of_association, proof_of_address, source_of_wealth_doc, director_register, shareholder_register, proof_of_tax_id, bank_statement, wolfsberg_questionnaire, msb_flow_form, flow_of_funds_diagram, aml_policy_procedures, ach_procedures, wire_procedures, customer_complaint_procedures, prohibited_jurisdictions_industries Attach the document to this beneficial owner or director. Must be the id of a person already on the application.