/documents (upload)
Upload supporting documentation for a KYC verification.
During the KYC onboarding process, it may be necessary to upload supporting documentation. This endpoint will support the upload of images of that documentation.
There are two options for structuring your uploads. You can either upload a single document at a time, or use a structure that allows for multiple documents in a single upload.
If using the Single Document request format, you will need to make two calls per document: one for the front, and one for the back.
Requests
Provide clear pictures
Blurry, dark, or otherwise illegible pictures of documents will not be approved, but Advanced KYC flow users should be extra cautious since documents are reviewed by an automated system. Please see Alloy's image guidelines here.
Authorization / Authentication
Apps using Access Token Authorization
Use a valid access token in a Authorization: Bearer request header.
See Authenticating with an Access Token for more details.
Apps using ECDSA Authentication
Both authsignature
and usersignature
headers are required for this request. The usersignature header should be generated with a keypair registered to the user (either registered from the /register endpoint or the /register_wallet endpoint).
See the section on ECDSA Authentication for more detail about ECDSA signature generation.
Requirements
- NOTE: Content-Type is different from all other endpoints. Set to
multipart/form-data
- NOTE: Document URL's are not supported. This endpoint requires you send a locally stored document
- Maximum request size is 20 mb
Handling the multipart/form-data
boundary
valueNodeJS
Do not manually set Content-Type, as this will not include a 'boundary.' Let your request package automatically detect the content type so that it can automatically generate a boundary.Python
multipart/form-data
is the default Content-Type for the python requests module; when using that module, don't set the header'sContent-Type
, but instead let therequests
module use its default, and it will properly determine the multipart/form-databoundary
value for you.
Single Document
Make two calls per document, one for the front and one for the back.
POST /0.2/documents HTTP/1.1
sandbox.silamoney.com
Content-Type: multipart/form-data
// if using OAuth2
Authorization: Bearer [GENERATED JWT TOKEN HERE]
// if using ECDSA
authsignature: [GENERATED AUTHSIGNATURE HEX STRING HERE]
usersignature: [GENERATED USERSIGNATURE HEX STRING HERE]
"files": {
"file": <file_binary_data>
},
"data": {
"header": {
"created": 1234567890,
"auth_handle": "handle.silamoney.eth",
"user_handle":"user.silamoney.eth",
"version": "0.2",
"reference": "<your unique id>"
},
"message": "header_msg",
"name": "CA drivers license", //required
"filename": "img_201901022_193206",
"hash": "046a9aaa83711158c3c4afa585a30be3bee8a34231ee72caac625faef48b4abe",
"mime_type": "image/jpeg",
"document_type": "id_drivers_license",
"description": "front of driver's license", //required
"verification_uuid": <uuid of verification record>, //required for Advanced KYC, optional for Classic
"provider": "ALLOY", //disregard for Classic
"is_front": true //required for Advanced KYC, disregard for Classic
}
***
HTTP/1.1 200 OK
{
"success": true,
"status": "SUCCESS",
"message": "File uploaded successfully.",
"response_time_ms": "1171",
"reference_id": "<your unique id>",
"document_id": "05e313a5-2cb4-4638-bf74-debe96b931ee"
}
const document = {
filePath: '/path/to/file', // In case of you have physical file path and using this SDK on server
fileObject: 'file object', // In case of you not have physical file path and using this SDK on client
fileBuffer: 'Uint8Array file buffer',// In case of you not have physical file path and using this SDK on client
filename: 'file-name',
mimeType: 'image/png',
documentType: 'doc_green_card',
name: 'file name', // Optional
description: 'some file description', // Optional
};
// fileObject and fileBuffer both are required if file send as object
// OR filePath is required if not send fileObject and fileBuffer
const res = await sila.uploadDocument(userHandle, userPrivateKey, document);
// Success Response Object
console.log(res.statusCode); // 200
console.log(res.data.success); // true
console.log(res.data.status); // SUCCESS
console.log(res.data.message); // File uploaded successfully
console.log(res.data.reference_id); // some-uuid-code
console.log(res.data.document_id); // other-uuid-code
import hashlib
f = open("/path/to/file", "rb")
file_contents = f.read()
f.close()
payload = {
"user_handle": user_handle,
"filename": "file-name",
"hash": hashlib.sha256(file_contents).hexdigest(),
"mime_type": "image/png",
"document_type": "id_drivers_license", # You can obtain this value from the listSupportedDocuments
"name": "some file name", # Optional
"description": "some file description" # Optional
}
response = silasdk.Documents.uploadDocument(app, payload, file_contents, user_private_key)
# Success Response Object
{
"success": true,
"status": "SUCCESS",
"message": "File uploaded successfully.",
"reference_id": "2624a0f6-e913-4e09-bfd7-c1bc10543483",
"document_id": "05e313a5-2cb4-4638-bf74-debe96b931ee"
}
UploadDocumentMessage message = UploadDocumentMessage.builder()
.userHandle("user_handle") // The user handle
.userPrivateKey("user_private_key") // The user's private key
.filePath("/path/to/file") // Full path to the file
.filename("logo-geko") // File name (without extension)
.mimeType("image/png") // File mime-type
.documentType("doc_green_card") // Document type
.identityType("other") // Optional. Identity type
.name("some file name") // Optional. Descriptive name of the document
.description("some file description") // Optional. General description of the document
.build();
ApiResponse response = api.uploadDocument(message);
// Success response
System.out.println(response.getStatusCode()); // 200
DocumentsResponse parsedResponse = (DocumentsResponse) response.getData();
System.out.println(parsedResponse.getSuccess()); // true
System.out.println(parsedResponse.getStatus()); // SUCCESS
System.out.println(parsedResponse.getMessage()); // File uploaded successfully
System.out.println(parsedResponse.getDocumentId());
System.out.println(parsedResponse.getReferenceId());
$userHandle = 'user.silamoney.eth';
$privateKey = 'some private key';
$filePath = '/path/to/file';
$fileName = 'some-image'; // The name of the file (without the extension)
$mimeType = 'image/png'; // The mime type of the file
$documentType = 'doc_green_card'; // One of Supported Document Types. You can get this from getDocumentTypes
$identityType = 'other'; // Matching Identity Type for Document Type. You can get this from getDocumentTypes
$name = 'file name'; // Optional. Descriptive name of the document.
$description = 'some file description'; // Optional. General description of the document.
$response = $client->uploadDocument($userHandle, $privateKey, $filePath, $fileName, $mimeType, $documentType, $identityType, $name, $description);
// or without optional parameteres name and description
$response = $client->uploadDocument($userHandle, $privateKey, $filePath, $fileName, $mimeType, $documentType, $identityType);
echo $response->getStatusCode(); // 200
echo $response->getData()->success; // TRUE
echo $response->getData()->status; // SUCCESS
echo $response->getData()->message; // File uploaded successfully.
echo $response->getData()->reference_id; // The reference uuid
echo $response->getData()->document_id; // The document uuid
//Load your informations
string identityType = null; // identityType is optional
string name = null; // Name is optional
string description = null; // Description is optional
var response = api.UploadDocument(userHandle, privateKey, filepath, filename, mimeType, documentType, identityType, name, description);
// Success Object Response
Console.WriteLine(response.StatusCode); // 200
var parsedResponse = (DocumentResponse)response.Data;
Console.WriteLine(parsedResponse.Success); // true
Console.WriteLine(parsedResponse.Status); // SUCCESS
Console.WriteLine(parsedResponse.Message); // File uploaded successfully
Console.WriteLine(parsedResponse.ReferenceId); // some-uuid-code
Console.WriteLine(parsedResponse.DocumentId); // other-uuid-code
Console.WriteLine(parsedResponse.ResponseTimeMs); // API responses time
Multiple Documents
Upload multiple documents in a single request. Can be used to upload a single document, front and back both, in a single request.
files
: the files you wish to upload. These must be in binary format, URLs are not supporteddata
: the header information and thefile_metadata
file_metadata
: the document metadata for each file you are uploading
Labels must match!
The labels you use in the "files" section must match the ones used in the "file_metadata" section.
POST /0.2/documents HTTP/1.1
sandbox.silamoney.com
Content-Type: multipart/form-data
// if using OAuth2
Authorization: Bearer [GENERATED JWT TOKEN HERE]
// if using ECDSA
authsignature: [GENERATED AUTHSIGNATURE HEX STRING HERE]
usersignature: [GENERATED USERSIGNATURE HEX STRING HERE]
"files": {
"my_file_1": <file_1_binary_data>,
"my_file_2": <file_2_binary_data>,
"your_file_1": <file_3_binary_data>
}
"data": {
"header": {
"created": 1234567890,
"auth_handle": "handle.silamoney.eth",
"user_handle":"user.silamoney.eth",
"version": "0.2",
"reference": "<your unique id>"
},
"file_metadata": {
"my_file_1": {
"name": "CA drivers license", //required
"filename": "img_201901022_193206",
"hash": "046a9aaa83711158c3c4afa585a30be3bee8a34231ee72caac625faef48b4abe",
"mime_type": "image/jpeg",
"document_type": "id_drivers_license",
"description": "front of driver's license", //required
"verification_uuid": <uuid of verification record>, //required for Advance KYC, optional for Classic
"provider": "ALLOY", //disregard for Classic
"is_front": true //required for Advanced KYC, disregard for Classic
},
"my_file_2": {
"name": "CA drivers license", //required
"filename": "img_201901022_193207",
"hash": "146a9aaa83711158c3c4afa585a30be3bee8a34231ee72caac625faef48b4abf",
"mime_type": "image/jpeg",
"document_type": "id_drivers_license",
"description": "back of driver's license", //required
"verification_uuid": <uuid of verification record>, //required for Advanced KYC, optional for Classic
"provider": "ALLOY", //disregard for Classic
"is_front": true //required for Advanced KYC, disregard for Classic
},
"your_file_1": {
"name": "CA drivers license", //required
"filename": "img_201901022_193208",
"hash": "246a9aaa83711158c3c4afa585a30be3bee8a34231ee72caac625faef48b4ace",
"mime_type": "image/jpeg",
"document_type": "id_drivers_license",
"description": "full driver's license", //required
"verification_uuid": <uuid of verification record>, //required for Advanced KYC, optional for Classic
"provider": "ALLOY", //disregard for Classic
"is_front": true //required for Advanced KYC, disregard for Classic
}
}
}
const document1 = {
filePath: '/path/to/file', // In case of you have physical file path and using this SDK on server
fileObject: 'file object', // In case of you not have physical file path and using this SDK on client
fileBuffer: 'Uint8Array file buffer',// In case of you not have physical file path and using this SDK on client
filename: 'file-name',
mimeType: 'image/png',
documentType: 'doc_green_card',
name: 'file name', // Optional
description: 'some file description', // Optional
};
const document2 = {
filePath: '/path/to/file', // In case of you have physical file path and using this SDK on server
fileObject: 'file object', // In case of you not have physical file path and using this SDK on client
fileBuffer: 'Uint8Array file buffer',// In case of you not have physical file path and using this SDK on client
filename: 'file-name',
mimeType: 'image/png',
documentType: 'doc_green_card',
name: 'file name', // Optional
description: 'some file description', // Optional
};
// fileObject and fileBuffer both are required if file send as object
// OR filePath is required if not send fileObject and fileBuffer
// support multiple documents upload (pass array of document object)
const res = await sila.uploadDocuments(userHandle, userPrivateKey, [document1, document2]);
// Success Response Object
console.log(res.statusCode); // 200
console.log(res.data.success); // true
console.log(res.data.status); // SUCCESS
console.log(res.data.message); // File uploaded successfully
console.log(res.data.reference_id); // some-uuid-code
console.log(res.data.document_id); // array of document_id
//Load your informations
string filepath0 = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, $"Resources{Path.DirectorySeparatorChar}logo-geko0.png");
string filepath1 = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, $"Resources{Path.DirectorySeparatorChar}logo-geko1.png");
var responseGetDocumentTypes = api.GetDocumentTypes();
var parsedResponse = (DocumentTypesResponse)responseGetDocumentTypes.Data;
var documentType = parsedResponse.DocumentTypes[0];
List<UploadDocument> uploadDocument = new List<UploadDocument>();
UploadDocument obj = new UploadDocument();
obj.FileName = "logo-geko0.png";
obj.FilePath = filepath0;
obj.Description = "test0";
obj.DocumentType = documentType.Name;
obj.MimeType = "image/png";
obj.Name = "logo-geko0";
uploadDocument.Add(obj);
obj = new UploadDocument();
obj.FileName = "logo-geko1.png";
obj.FilePath = filepath1;
obj.Description = "test1";
obj.DocumentType = documentType.Name;
obj.MimeType = "image/png";
obj.Name = "logo-geko1";
uploadDocument.Add(obj);
var response = api.UploadDocuments(userHandle, privateKey, uploadDocument);
// Success Object Response
Console.WriteLine(response.StatusCode); // 200
var parsedResponseDoc = (UploadDocumentsResponse)response.Data;
Console.WriteLine(parsedResponseDoc.Success); // true
Console.WriteLine(parsedResponseDoc.Status); // SUCCESS
Console.WriteLine(parsedResponseDoc.Message); // File uploaded successfully
Console.WriteLine(parsedResponseDoc.ReferenceId); // some-uuid-code
Console.WriteLine(parsedResponseDoc.DocumentId); // array
Console.WriteLine(parsedResponseDoc.UnsuccessfulUploads); // array
Console.WriteLine(parsedResponseDoc.ResponseTimeMs); // API responses time
ArrayList<UploadDocument> uploadDocumentList = new ArrayList<>();
uploadDocumentList.add(UploadDocument.builder()
.filePath("/path/to/file_1") // Full path to the file
.filename("logo-geko") // File name (without extension)
.mimeType("image/png") // File mime-type
.documentType("doc_green_card") // Document type
.name("some file name") // Optional. Descriptive name of the document
.description("some file description") // Optional. General description of the document_1
.build());
uploadDocumentList.add(UploadDocument.builder()
.filePath("/path/to/file_2") // Full path to the file
.filename("tricolor") // File name (without extension)
.mimeType("image/png") // File mime-type
.documentType("doc_green_card") // Document type
.name("some file name") // Optional. Descriptive name of the document
.description("some file description") // Optional. General description of the document_2
.build());
UploadDocumentsMessage message = UploadDocumentsMessage.builder()
.userHandle("user_handle") // The user handle
.userPrivateKey("user_private_key") // The user's private key
.uploadDocumentList(uploadDocumentList).build();
ApiResponse response = api.uploadDocuments(message);
// Success response
System.out.println(response.getStatusCode()); // 200
UploadDocumentsResponse parsedResponse = (UploadDocumentsResponse) response.getData();
System.out.println(parsedResponse.getSuccess()); // true
System.out.println(parsedResponse.getStatus()); // SUCCESS
System.out.println(parsedResponse.getMessage()); // File uploaded successfully
System.out.println(parsedResponse.getDocumentIds());
System.out.println(parsedResponse.getReferenceId());
import hashlib
f = open(os.path.dirname(os.path.realpath(__file__)) +
"/images/logo-geko.png", "rb")
fileContents_1 = f.read()
f.close()
a = open(os.path.dirname(os.path.realpath(__file__)) +
"/images/logo-geko.png", "rb")
fileContents_2 = a.read()
a.close()
payload = {
"user_handle": user_handle,
"file_metadata" : {
"file_1":{
"filename": "logo-geko1",
"hash": hashlib.sha256(fileContents_1).hexdigest(),
"mime_type": "image/png",
"document_type": "id_drivers_license",
"identity_type": "license",
},
"file_2":{
"filename": "logo-geko1",
"hash": hashlib.sha256(fileContents_2).hexdigest(),
"mime_type": "image/png",
"document_type": "id_drivers_license",
"identity_type": "license",
}
}
}
fileContent = {
"file_1" : fileContents_1,
"file_2" : fileContents_2
}
response = silasdk.Documents.uploadDocuments(app, payload, fileContent, user_private_key)
$userHandle = 'user.silamoney.eth';
$privateKey = 'some private key';
$documents = [];
$documents["file_1"] = [
"filePath" => "/path/to/file",
"filename" => "file-name",
"mimeType" => "application/pdf",
"documentType" => "id_drivers_permit"
];
$documents["file_2"] = [
"filePath" => "/path/to/file",
"filename" => "another-file-name",
"mimeType" => "image/jpeg",
"documentType" => "id_drivers_permit"
];
$response = self::$config->api->uploadDocuments($handle, $privateKey, $documents);
echo $response->getStatusCode(); // 200
echo $response->getData()->success; // TRUE
echo $response->getData()->status; // SUCCESS
echo $response->getData()->message; // File uploaded successfully.
echo $response->getData()->reference_id; // The reference uuid
echo $response->getData()->document_id; // The document uuid
Request Attributes
Key | Type | Description |
---|---|---|
name | string | Required. Descriptive name of the document. (Max allowed length 100 chars) |
filename | string | Optional. Do not include the file extension. (Max allowed length 100 chars) |
hash | string | Optional. SHA-256 hash of the file contents |
mime_type | string | Optional. MIME type for one of Supported Image Formats |
document type | string | Optional. One of Supported Document Types |
description | string | Required. General description of the document. (Max allowed length 255 chars) |
Advanced KYC Specific Attributes
Disregard if using Classic KYC
Key | Type | Description |
---|---|---|
verification_uuid | string | Required. Verification UUID for the verification record the document is for. Can be found by calling /get_verifications. |
provider | string | Optional. Defaults to ALLOY . Currently no other valid options. |
is_front | boolean | Required. Defaults to true . Must be supplied and set to false for the back of documents. |
Supported Image Formats
Image Format | Image Extension | MIME type |
---|---|---|
PNG | .png | image/png |
JPG | .jpg | image/jpeg |
application/pdf |
Supported Document Types
Supported Doc Types for Advanced KYC Flow
For Advanced KYC, the below table does not apply. Your end users will need to upload one of the file documents:
Driver's license / state ID
PassportBusiness entities: doc upload is not supported for business entities. Additional verification, if needed, will be done manually by the Sila BankOps team.
(see also /document_types)
Document Type long-form (label) | Document Type short‑form (name) |
---|---|
1040 Tax Return | tax_1040 |
Birth Certificate | vtl_birth_certificate |
Court Order for Name Change | doc_name_change |
Divorce Decree | vtl_divorce |
Driver's permit | id_drivers_permit |
IRS form W2 | tax_w2 |
Lease agreement | doc_lease |
Marriage Certificate | vtl_marriage |
Military Dependent's ID Card | id_military_dependent |
Military ID | id_military |
Mortgage agreement | doc_mortgage |
NYC ID Card | id_nyc_id |
Other Document | other_doc |
Other ID | other_id |
Passport | id_passport |
Pay Stub Documentation | doc_paystub |
Permanent Resident Card (or Green Card) | doc_green_card |
Social Security Administration documentation (includes 4029) | doc_ssa |
Social Security Card | doc_ss_card |
State ID card | id_state |
State-issued driver's license | id_drivers_license |
Tax Form 1095 | tax_1095 |
Tax Form 1099 | tax_1099 |
Tuition Statement | doc_tuition |
Unemployment Benefits Letter | doc_uo_benefits |
US Passport Card | id_passport_card |
Utility bill | doc_utility |
W4 Withholding Allowance Certificate | tax_W4 |
Account Verification Letter | verification_letter |
Bank Statement | bank_statement |
Responses
Status Code | success | Description |
---|---|---|
200 | true | File upload was successful |
400 | false | Document upload not permitted for users who have not started KYC |
400 | false | Uploaded file's signature does not match file_hash |
400 | false | Invalid document_type |
400 | false | Unsupported or mismatched mime_type |
See Also:
Updated about 2 months ago
The following are secondary endpoints that are either dependent on or used in conjunction with the primary /documents endpoint as well as other supporting documentation needed for triaging KYC failures.