Upload File
/api/v1/users/me/files/uploadUploads a base64-encoded file. If caseId is provided the file is attached to that case as an attachment on a case the patient owns. If caseId is omitted the file is saved as a general user document. isPHI and isRestricted always start as false.
https://api.care360-next.carevalidate.com/api/v1/users/me/files/uploadhttps://api-staging.care360-next.carevalidate.com/api/v1/users/me/files/uploadSend the file as base64 in data. Chunked / multipart upload is not supported. No application-layer size cap is enforced — App Engine / proxy limits apply transitively.
Headers
cv-api-keystringrequiredYour unique API key for authentication.
AuthorizationstringrequiredBearer access token from /verify-otp.
Content-TypestringrequiredMust be application/json.
Request Body
namestringrequiredDisplay file name. Length 1–255.
lab-result.pdfdatastringrequiredBase64-encoded file bytes. Length ≥ 1.
caseIdstringoptionalUUID of a case owned by the patient in the calling organization. If omitted the file is saved as a general user document not linked to any case.
mimeTypestringrequiredMIME type of the upload. Must be on the allowlist.
Behavior
A failed bucket write is followed by a soft-delete of the just-created DB row, so the row will not appear in subsequent listings.
The upload response does not include uploadedBy. If your client needs uploader info immediately, follow up with GET /me/files/:id/metadata.
Example Request
- cURL
- JavaScript
- Python
curl -X POST '<BASE_URL>/api/v1/users/me/files/upload' \
-H 'cv-api-key: <redacted>' \
-H 'Authorization: Bearer <accessToken>' \
-H 'Content-Type: application/json' \
-d '{
"name": "lab-result.pdf",
"caseId": "550e8400-e29b-41d4-a716-446655440111",
"mimeType": "application/pdf",
"data": "JVBERi0xLjQK..."
}'
# Without caseId (general document)
curl -X POST '<BASE_URL>/api/v1/users/me/files/upload' \
-H 'cv-api-key: <redacted>' \
-H 'Authorization: Bearer <accessToken>' \
-H 'Content-Type: application/json' \
-d '{
"name": "consent-form.pdf",
"mimeType": "application/pdf",
"data": "JVBERi0xLjQK..."
}'
const buffer = await file.arrayBuffer();
const base64 = btoa(String.fromCharCode(...new Uint8Array(buffer)));
const response = await fetch(
'<BASE_URL>/api/v1/users/me/files/upload',
{
method: 'POST',
headers: {
'cv-api-key': '<redacted>',
'Authorization': 'Bearer <accessToken>',
'Content-Type': 'application/json',
},
body: JSON.stringify({
name: 'lab-result.pdf',
caseId: '<CASE_ID>',
mimeType: 'application/pdf',
data: base64,
}),
}
);
const data = await response.json();
console.log(data);
import base64
import requests
with open('lab-result.pdf', 'rb') as f:
data = base64.b64encode(f.read()).decode('ascii')
response = requests.post(
'<BASE_URL>/api/v1/users/me/files/upload',
headers={
'cv-api-key': '<redacted>',
'Authorization': 'Bearer <accessToken>',
'Content-Type': 'application/json',
},
json={
'name': 'lab-result.pdf',
'caseId': '<CASE_ID>',
'mimeType': 'application/pdf',
'data': data,
},
)
print(response.json())
Responses
▶200SuccessReturns the upload result. Note: uploadedBy is not included.
{
"status": 200,
"success": true,
"data": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"fileName": "lab-result.pdf",
"isPHI": false,
"isRestricted": false,
"caseId": "550e8400-e29b-41d4-a716-446655440111",
"createdAt": "2026-04-30T12:34:56.000Z"
}
}
▶200Success — general documentcaseId was omitted. Returns the new UserDocument. Visible in admin panel under Documents → User Documents. Not returned by GET /me/files.
{
"status": 200,
"success": true,
"data": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"fileName": "consent-form.pdf",
"isPHI": false,
"isRestricted": false,
"caseId": null,
"createdAt": "2026-04-30T12:34:56.000Z"
}
}
▶400Validation errorcv-api-key missing; body fails Zod (missing field, name too long, non-UUID caseId, unsupported mimeType, empty data).
{
"status": 400,
"success": false,
"error": "Validation failed",
"code": "VALIDATION_ERROR"
}
▶401Authentication failure
{
"status": 401,
"success": false,
"error": "Invalid or expired token",
"code": "VALIDATION_ERROR"
}
▶403Case not ownedcaseId does not belong to the patient or to the calling org.
{
"status": 403,
"success": false,
"error": "You do not have access to this case",
"code": "VALIDATION_ERROR"
}
▶500Storage failureBucket write failed. The placeholder DB row was rolled back via soft-delete.
{
"status": 500,
"success": false,
"error": "Failed to upload file",
"code": "INTERNAL_ERROR"
}