Skip to content
Get Started

Data Plane

Files

POST /v1/files, GET /v1/files, DELETE /v1/files/{file_key} — upload reports, retrieve extracted text, list, and delete.

Upload a health document to the Subject’s store. Mirobody saves the original first, then in the background extracts its readable text — OCR for PDFs and images, a straight conversion for spreadsheets and text files — and runs the same standardization pipeline as POST /v1/standardize over it, so an uploaded lab report also lands as standardized records. The agent reads both when it answers.

POST /v1/files
Authorization: Bearer mb_live_*
Content-Type: multipart/form-data
FieldDescription
fileThe document (PDF / image / Excel / CSV).
userSubject the file belongs to. Optional — omitting it falls back to your account’s default Subject, so always pass it for per-end-user isolation.
retentionOptional here (unlike POST /v1/data, where it’s required). Same values as Data retention.
session_idOptional; scopes retention=session uploads to a session.
Terminal window
curl https://api.mirobody.ai/v1/files \
-H "Authorization: Bearer $MIROBODY_API_KEY" \
-F "user=alice" \
-F "file=@checkup_2026.pdf"

Response:

{
"object": "file",
"id": "AUmIn_R-Ddg.../b/bM--fG29X....pdf",
"filename": "checkup_2026.pdf",
"bytes": 20544,
"status": "processed",
"created_at": 1782924296,
"subject": "alice"
}

The file’s identifier is id (a slash-containing key) — use it as {file_key} in the fetch and delete calls below. created_at is epoch seconds.

An upload makes the document’s text readable by the agent, and Mirobody also pulls the report’s readings out of it — standardized exactly like a POST /v1/data write — and stores them as records. Query them from GET /v1/data without re-entering anything; re-uploading the same file creates no duplicates. Prefer POST /v1/standardize when you’d rather run that extraction yourself and check the readings first. Already have structured records? Send them to POST /v1/data.

GET /v1/files?user=alice
Authorization: Bearer mb_live_*
{
"object": "list",
"data": [
{
"object": "file",
"id": "AUmIn_R-Ddg.../b/bM--fG29X....pdf",
"file_key": "AUmIn_R-Ddg.../b/bM--fG29X....pdf",
"filename": "checkup_2026.pdf",
"file_type": "application/pdf",
"bytes": 20544,
"created_at": 1782924296
}
],
"subject": "alice"
}

data holds the files; subject echoes the Subject. Each item exposes both id and file_key (identical values). created_at is epoch seconds, matching the upload response.

GET /v1/files/{file_key}?user=alice
Authorization: Bearer mb_live_*

Returns the extracted text for one file — the same content the agent reads:

{
"object": "file",
"id": "AUmIn_R-Ddg.../b/bM--fG29X....pdf",
"filename": "checkup_2026.pdf",
"extracted_text": "Annual checkup 2026-06-16\nFasting glucose 97 mg/dL (ref 70-110)\n...",
"abstract": "",
"subject": "alice"
}

extracted_text can be empty while the file’s text is still being processed. abstract may also be empty; it isn’t generated for every file type.

For large exports or realtime capture, wss://…/v1/files/stream uploads over one socket with chunking and progress. Auth rides the query string (browsers can’t set WebSocket headers):

wss://api.mirobody.ai/v1/files/stream?key=mb_live_...&user=alice&retention=permanent

Frame sequence (all JSON text frames):

  1. Server → you: {"type": "connection_established"} — send nothing before this.
  2. You → server: {"type": "upload_start", "messageId": "<batch-id>", "files": [{"filename", "contentType", "size"}]} — one messageId for the whole batch.
  3. You → server, per 256 KB chunk: {"type": "upload_chunk", "messageId", "filename", "chunk": "<base64>", "chunkIndex", "totalChunks"}.
  4. You → server: {"type": "upload_end", "messageId"} → server replies upload_end_response when every original file has been stored. Its text may still be processing.

Same 100 MB per-file cap, same Subject isolation, and the stored files are identical to a POST /v1/files upload — list them with GET /v1/files.

DELETE /v1/files/{file_key}?user=alice
Authorization: Bearer mb_live_*

Removes the file from the API surface immediately (404 if it isn’t the Subject’s file or is already deleted):

{ "object": "file", "id": "AUmIn_R-Ddg.../b/bM--fG29X....pdf", "deleted": true, "subject": "alice" }

Time-bounded uploads are also removed automatically at retention expiry — an expired file disappears from every GET /v1/files* read immediately and is then permanently deleted. To erase everything about a Subject at once, use DELETE /v1/subjects/{user} — see Compliance.