Skip to content

Upload evidence to a control

POST
/controls/{controlId}/evidence
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=example

Streams 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.

controlId
required
string format: uuid
filename
string
summary
string
description
string
effectiveDate
string
isSensitive
string
Allowed values: true false

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
file
required
string format: binary
summary
string
description
string
effectiveDate
string
isSensitive
string

Success

Media typeapplication/json
object
success
required
boolean
data
required
object
evidence
required
object
id
required
string format: uuid
organizationId
required
string format: uuid
controlId
required
string format: uuid
controlDisplayId
required
string | null
controlName
required
string | null
testType
required
string
source
required
string
status
required
string
summary
required
string | null
isSensitive
required
boolean
collectedAt
required
string format: date-time
expiresAt
required
string | null format: date-time
supersededBy
required
string | null format: uuid
key
additional properties
file
required
object
id
required
string format: uuid
filename
required
string
mimeType
required
string
sizeBytes
required
integer
contentHash
required
string
scanStatus
required
string
timestamp
required
string format: date-time
requestId
string
message
string
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

Media typeapplication/json
object
success
required
boolean
error
required
string
code
required
string
details
timestamp
required
string format: date-time
requestId
string
Example
{
"success": false,
"error": "Bad request",
"code": "BAD_REQUEST",
"timestamp": "2026-08-19T09:41:12.004Z",
"requestId": "req_01J5X8ZC3K4T7Q9M2W6B0N1V4H"
}

Unauthorized

Media typeapplication/json
object
success
required
boolean
error
required
string
code
required
string
details
timestamp
required
string format: date-time
requestId
string
Example
{
"success": false,
"error": "Unauthorized",
"code": "UNAUTHORIZED",
"timestamp": "2026-08-19T09:41:12.004Z",
"requestId": "req_01J5X8ZC3K4T7Q9M2W6B0N1V4H"
}

Storage quota exhausted for the organization plan

Media typeapplication/json
object
success
required
boolean
error
required
string
code
required
string
details
timestamp
required
string format: date-time
requestId
string
Example
{
"success": false
}

Forbidden — missing scope

Media typeapplication/json
object
success
required
boolean
error
required
string
code
required
string
details
timestamp
required
string format: date-time
requestId
string
Example
{
"success": false,
"error": "Forbidden",
"code": "FORBIDDEN",
"timestamp": "2026-08-19T09:41:12.004Z",
"requestId": "req_01J5X8ZC3K4T7Q9M2W6B0N1V4H"
}

Not found

Media typeapplication/json
object
success
required
boolean
error
required
string
code
required
string
details
timestamp
required
string format: date-time
requestId
string
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

Media typeapplication/json
object
success
required
boolean
error
required
string
code
required
string
details
timestamp
required
string format: date-time
requestId
string
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)

Media typeapplication/json
object
success
required
boolean
error
required
string
code
required
string
details
timestamp
required
string format: date-time
requestId
string
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

Media typeapplication/json
object
success
required
boolean
error
required
string
code
required
string
details
timestamp
required
string format: date-time
requestId
string
Example
{
"success": false,
"error": "Validation failed",
"code": "VALIDATION_ERROR",
"timestamp": "2026-08-19T09:41:12.004Z",
"requestId": "req_01J5X8ZC3K4T7Q9M2W6B0N1V4H"
}

Rate limit exceeded

Media typeapplication/json
object
success
required
boolean
error
required
string
code
required
string
details
timestamp
required
string format: date-time
requestId
string
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

Media typeapplication/json
object
success
required
boolean
error
required
string
code
required
string
details
timestamp
required
string format: date-time
requestId
string
Example
{
"success": false,
"error": "Service unavailable",
"code": "SERVICE_UNAVAILABLE",
"timestamp": "2026-08-19T09:41:12.004Z",
"requestId": "req_01J5X8ZC3K4T7Q9M2W6B0N1V4H"
}