Upload evidence to a control
const url = 'https://api.vendorica.com/v1/controls/2489E9AD-2EE2-8E00-8EC9-32D5F69181C0/evidence?isSensitive=true';const form = new FormData();form.append('file', 'file');form.append('summary', 'example');form.append('description', 'example');form.append('effectiveDate', 'example');form.append('isSensitive', 'example');
const options = {method: 'POST', headers: {Authorization: 'Bearer <token>'}};
options.body = form;
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}curl --request POST \ --url 'https://api.vendorica.com/v1/controls/2489E9AD-2EE2-8E00-8EC9-32D5F69181C0/evidence?isSensitive=true' \ --header 'Authorization: Bearer <token>' \ --header 'Content-Type: multipart/form-data' \ --form file=@file \ --form summary=example \ --form description=example \ --form effectiveDate=example \ --form isSensitive=exampleStreams a document into the control as its current evidence, superseding whatever it replaces — the same lifecycle as the app. Idempotent on content: if the target already carries CURRENT bytes with this hash, the existing record is returned with 200 and Idempotent-Replay: true instead of filing a duplicate. Sending X-Checksum-Sha256 lets that be answered BEFORE the body is transferred, which is what makes a interrupted bulk run cheap to resume. The response file.scanStatus reports the asynchronous malware-scan state — a document is not necessarily downloadable the moment this returns.
Authorizations
Section titled “Authorizations”Parameters
Section titled “Parameters”Path Parameters
Section titled “Path Parameters”Query Parameters
Section titled “Query Parameters”Request Bodyrequired
Section titled “Request Bodyrequired”Either multipart/form-data with a file part (metadata in sibling text fields), or a raw application/octet-stream body (metadata in the query string, filename via ?filename=, X-Filename or Content-Disposition). Raw bodies MUST send Content-Length. Optional X-Checksum-Sha256 is verified against the stored bytes; on mismatch nothing is written.
object
Responses
Section titled “Responses”Success
object
object
object
object
Example
{ "success": true, "data": { "evidence": { "id": "821d0c28-fdba-461e-8909-ffa75dbd6d99", "organizationId": "04d3036d-072e-47bd-8c0d-501a16f51f3a", "controlId": "2ab81157-94c3-48cf-8b6b-9924ea620d60", "controlDisplayId": "string", "controlName": "string", "testType": "string", "source": "string", "status": "string", "summary": "string", "isSensitive": true, "collectedAt": "2026-08-19T09:41:12.004Z", "expiresAt": "2026-08-19T09:41:12.004Z", "supersededBy": "a6bfe6d0-5218-4c96-8159-be8f1b46f4d1" }, "file": { "id": "6f552bf3-3414-4c63-8bc1-db20962bf9ac", "filename": "string", "mimeType": "string", "sizeBytes": 1, "contentHash": "string", "scanStatus": "string" } }, "timestamp": "2026-08-19T09:41:12.004Z", "requestId": "req_01J5X8ZC3K4T7Q9M2W6B0N1V4H", "message": "string"}Validation error
object
Example
{ "success": false, "error": "Bad request", "code": "BAD_REQUEST", "timestamp": "2026-08-19T09:41:12.004Z", "requestId": "req_01J5X8ZC3K4T7Q9M2W6B0N1V4H"}Unauthorized
object
Example
{ "success": false, "error": "Unauthorized", "code": "UNAUTHORIZED", "timestamp": "2026-08-19T09:41:12.004Z", "requestId": "req_01J5X8ZC3K4T7Q9M2W6B0N1V4H"}Storage quota exhausted for the organization plan
object
Example
{ "success": false}Forbidden — missing scope
object
Example
{ "success": false, "error": "Forbidden", "code": "FORBIDDEN", "timestamp": "2026-08-19T09:41:12.004Z", "requestId": "req_01J5X8ZC3K4T7Q9M2W6B0N1V4H"}Not found
object
Example
{ "success": false, "error": "Resource not found", "code": "NOT_FOUND", "timestamp": "2026-08-19T09:41:12.004Z", "requestId": "req_01J5X8ZC3K4T7Q9M2W6B0N1V4H"}Content-Length is required for a raw (non-multipart) body
object
Example
{ "success": false, "error": "Content-Length is required for this upload", "code": "LENGTH_REQUIRED", "timestamp": "2026-08-19T09:41:12.004Z", "requestId": "req_01J5X8ZC3K4T7Q9M2W6B0N1V4H"}Upload exceeds API_UPLOAD_MAX_BYTES (details.maxBytes)
object
Example
{ "success": false, "error": "Upload exceeds the maximum allowed size", "code": "PAYLOAD_TOO_LARGE", "details": { "maxBytes": 262144000 }, "timestamp": "2026-08-19T09:41:12.004Z", "requestId": "req_01J5X8ZC3K4T7Q9M2W6B0N1V4H"}Rejected file type, unverifiable content, or checksum mismatch
object
Example
{ "success": false, "error": "Validation failed", "code": "VALIDATION_ERROR", "timestamp": "2026-08-19T09:41:12.004Z", "requestId": "req_01J5X8ZC3K4T7Q9M2W6B0N1V4H"}Rate limit exceeded
object
Example
{ "success": false, "error": "Too many requests", "code": "TOO_MANY_REQUESTS", "timestamp": "2026-08-19T09:41:12.004Z", "requestId": "req_01J5X8ZC3K4T7Q9M2W6B0N1V4H"}Object storage not configured
object
Example
{ "success": false, "error": "Service unavailable", "code": "SERVICE_UNAVAILABLE", "timestamp": "2026-08-19T09:41:12.004Z", "requestId": "req_01J5X8ZC3K4T7Q9M2W6B0N1V4H"}