# GetSafeDocs API Documentation Welcome to the GetSafeDocs API! This documentation covers all available endpoints for secure document sharing, messaging, tracking, document requests, and more. --- ## Authentication The API uses session-based authentication. After successful login, a session is established and subsequent requests are authenticated automatically. ### Register - **Endpoint:** `POST /api/register.php` - **Body (JSON):** `{ "email": "user@example.com", "password": "yourpassword" }` - **Response:** `{ "success": true, "account_id": 123 }` or `{ "error": "..." }` ### Login - **Endpoint:** `POST /api/login.php` - **Body (JSON):** `{ "email": "user@example.com", "password": "yourpassword" }` - **Response:** `{ "success": true, "account_id": 123 }` or `{ "error": "..." }` - **Note:** Establishes a session for subsequent authenticated requests ### Logout - **Endpoint:** `POST /api/logout.php` - **Response:** `{ "success": true, "message": "Logged out successfully" }` ### Refresh Session - **Endpoint:** `POST /api/refresh_token.php` - **Response:** `{ "success": true, "account_id": 123 }` or `{ "error": "Not authenticated" }` --- ## Messages ### Send Message - **Endpoint:** `POST /api/send_message.php` - **Content-Type:** `application/x-www-form-urlencoded` - **Fields:** - `recipient` (string, required) - `subject` (string, required) - `body` (string, required) - `uploaded_file_ids` (string, optional) - Comma-separated list of file IDs from previous uploads - **Response:** `{ "success": true, "message_id": 123 }` or `{ "error": "..." }` - **Note:** Files must be uploaded separately using the file upload endpoints before sending the message ### List Sent Messages - **Endpoint:** `GET /api/list_messages.php?limit=20&offset=0` - **Response:** ``` { "success": true, "messages": [ { "message_id": 123, "subject": "Subject", "created_at": "...", "status": "sent", "recipients": "..." } ], "total": 42, "limit": 20, "offset": 0 } ``` ### List Received Messages - **Endpoint:** `GET /api/list_received_messages.php?limit=20&offset=0` - **Response:** ``` { "success": true, "messages": [ { "message_id": 456, "subject": "Subject", "created_at": "...", "status": "sent", "sender_email": "..." } ], "total": 42, "limit": 20, "offset": 0 } ``` ### View Message Details - **Endpoint:** `GET /api/message_details.php?message_id=123` - **Response:** ``` { "success": true, "message": { "message_id": 123, "subject": "...", "body": "...", "created_at": "...", "status": "...", "sender_email": "...", "recipients": ["..."], "attachments": [ { "file_id": 789, "file_name": "..." } ] } } ``` ### Delete Message - **Endpoint:** `POST /api/delete_message.php` - **Body (JSON):** `{ "message_id": 123 }` - **Response:** `{ "success": true }` or `{ "error": "..." }` --- ## Attachments ### Download Attachment - **Endpoint:** `GET /api/download_attachment.php?file_id=789` - **Response:** File download (if authorized) or JSON error --- ## File Uploads All file uploads now use a secure multi-step signed URL process for improved security and performance. This applies to both authenticated users and document request uploads. ### General File Upload Process #### Step 1: Get Signed Upload URL - **Endpoint:** `POST /get_signed_url.php` - **Authentication:** Required (for authenticated uploads) - **Content-Type:** `application/json` - **Body (JSON):** ``` { "filename": "document.pdf", "contentType": "application/pdf", "fileSize": 1024000 } ``` - **Response:** ``` { "success": true, "signedUrl": "https://storage.googleapis.com/bucket/temp/path?signature=...", "tempBucketPath": "user_uploads/uuid/document.pdf", "uuid": "12345678-1234-1234-1234-123456789012", "uploadToken": "base64encodedtoken" } ``` #### Step 2: Upload File to GCP - **Method:** `PUT` - **URL:** Use the `signedUrl` from Step 1 - **Content-Type:** Use the `contentType` from Step 1 - **Body:** Raw file data - **Response:** HTTP 200 on success #### Step 3: Process Upload - **Endpoint:** `POST /process_cloud_upload.php` - **Authentication:** Required (for authenticated uploads) - **Content-Type:** `application/json` - **Body (JSON):** ``` { "tempBucketPath": "user_uploads/uuid/document.pdf", "filename": "document.pdf", "contentType": "application/pdf", "fileSize": 1024000, "uuid": "12345678-1234-1234-1234-123456789012", "uploadToken": "base64encodedtoken" } ``` - **Response:** ``` { "success": true, "file_id": "temp_1234567890", "scan_result": { "rating": 0, "risk": "Clean", "access_uuid": "access_1234567890" } } ``` ### Upload File - **Endpoint:** `POST /api/upload_file.php` - **Authentication:** Required - **Content-Type:** `application/json` - **Body (JSON):** Same as Step 3 above - **Response:** Same as Step 3 above - **Note:** This endpoint combines all three steps for convenience, but still uses the signed URL process internally ### Get Document Request Signed URL - **Endpoint:** `POST /api/get_document_request_signed_url.php` - **Authentication:** Token-based (via `access_token` parameter) - **Purpose:** Get a signed URL for uploading files to a document request without requiring user authentication - **Content-Type:** `application/json` - **Body (JSON):** ``` { "filename": "document.pdf", "contentType": "application/pdf", "fileSize": 1024000, "access_token": "abc123def456" } ``` - **Response:** Same format as general signed URL endpoint - **Validations:** - Validates document request token is active and not expired - Enforces document request file size limits - Validates file types against allowed types (if specified) - Checks security restrictions (forbidden file types) - **Note:** This is a specialized version of `/get_signed_url.php` designed specifically for document request uploads with token-based authentication instead of session-based authentication ### Benefits of Signed URL Uploads - **Security:** Upload tokens prevent replay attacks and unauthorized uploads - **Performance:** Direct upload to GCP without going through the web server - **Scalability:** Reduces server load and bandwidth usage - **Reliability:** Better error handling and progress tracking - **Consistency:** All uploads follow the same secure pattern - **Token-based Access:** Document requests can accept uploads without requiring user accounts ### File Type Validation All file uploads are validated using centralized functions in `functions.php` to ensure consistency across all endpoints. **For current file type support, see:** [File Types Reference](/file_types.php) (HTML) | [JSON](/file_types.php?format=json) | [Markdown](/file_types.php?format=markdown) The system supports: - **Free Tier:** 60+ file types including documents, images, archives, and code files - **Premium/Enterprise:** All free tier types plus video, audio, and design files - **Forbidden:** Executable files and scripts blocked for security reasons across all tiers File type lists are maintained in `includes/functions.php` via these functions: - `getAllowedFileExtensions()` - Free tier supported types - `getPremiumFileExtensions()` - Premium-only additional types - `getForbiddenFileExtensions()` - Security-blocked types #### Validation Process: 1. **Client-side pre-validation** - File type checking before upload 2. **Server-side extension validation** - Forbidden extension check 3. **Tier-based restrictions** - User tier determines allowed types 4. **Content-Type validation** - MIME type verification 5. **Upload token validation** - Cryptographic token verification 6. **MIME type verification** - Post-upload content inspection 7. **Malware scanning** - QuickSand static analysis #### Error Responses: - **Forbidden file type:** `{ "success": false, "message": "File type 'exe' is not allowed for security reasons..." }` - **Unsupported for tier:** `{ "success": false, "message": "File type 'mp4' is not supported for free accounts..." }` - **MIME mismatch:** `{ "success": false, "message": "File content does not match the 'pdf' extension..." }` --- ### Message Tracking - **Endpoint:** `GET /api/message_tracking.php?message_id=123` - **Response:** ``` { "success": true, "message_id": 123, "subject": "...", "created_at": "...", "tracking": [ { "activity_type": "message_sent", "activity_timestamp": "...", "ip_address": "...", "user_agent": "...", "recipient_email": "..." } ] } ``` --- ## Replies ### Add Reply - **Endpoint:** `POST /api/add_reply.php` - **Body (JSON):** `{ "message_id": 123, "reply_text": "...", "parent_reply_id": 5 }` - **Response:** `{ "success": true, "reply_id": 42 }` or `{ "error": "..." }` ### List Replies - **Endpoint:** `GET /api/list_replies.php?message_id=123` - **Response:** ``` { "success": true, "replies": [ { "reply_id": 42, "message_id": 123, "recipient_id": 7, "reply_text": "...", "created_at": "...", "is_read": 0, "parent_reply_id": null, "is_sender_reply": 1, "viewed_at": null } ] } ``` ### Mark Reply as Read - **Endpoint:** `POST /api/mark_reply_read.php` - **Body (JSON):** `{ "reply_id": 42 }` - **Response:** `{ "success": true }` or `{ "success": true, "already_read": true }` --- ## Document Requests Document requests allow external users to upload files using a secure token without requiring an account. **Note:** The API field is called `access_token` in both the documentation and implementation. ### Create Document Request - **Endpoint:** `POST /api/create_document_request.php` - **Authentication:** Required (premium users only) - **Body (JSON):** ``` { "request_name": "Contract Documents", "description": "Please upload the signed contract and supporting documents", "allow_multiple_submissions": true, "max_file_size_mb": 50, "max_files_per_submission": 10, "allowed_file_types": "pdf,doc,docx", "require_email": true, "require_subject": false, "require_message": true, "expiry_days": 30 } ``` - **Response:** ``` { "success": true, "message": "Document request created successfully", "request": { "request_id": 123, "request_name": "Contract Documents", "description": "Please upload the signed contract and supporting documents", "access_token": "abc123def456", "allow_multiple_submissions": true, "max_file_size_mb": 50, "max_files_per_submission": 10, "allowed_file_types": "pdf,doc,docx", "require_email": true, "require_subject": false, "require_message": true, "expiry_date": "2024-02-15 10:30:00", "expiry_days": 30, "upload_url": "../document_request_upload.php?token=abc123def456", "created_at": "2024-01-16 10:30:00" } } ``` - **Error Responses:** - `{ "success": false, "message": "Not authenticated" }` (401) - `{ "success": false, "message": "Document request creation is a premium feature..." }` (403) - `{ "success": false, "message": "Request name is required" }` (400) - `{ "success": false, "message": "Maximum file size must be between 1 and X MB..." }` (400) ### Upload Document Request File **Note:** This endpoint now uses a multi-step signed URL upload process for improved security and performance. #### Step 1: Get Signed Upload URL (Document Requests) - **Endpoint:** `POST /api/get_document_request_signed_url.php` - **Authentication:** Not required (token-based via `access_token`) - **Content-Type:** `application/json` - **Body (JSON):** ``` { "filename": "document.pdf", "contentType": "application/pdf", "fileSize": 1024000, "access_token": "abc123def456" } ``` - **Response:** ``` { "success": true, "signedUrl": "https://storage.googleapis.com/bucket/temp/path?signature=...", "tempBucketPath": "document_requests/uuid/document.pdf", "uuid": "12345678-1234-1234-1234-123456789012", "uploadToken": "base64encodedtoken" } ``` - **Error Responses:** - `{ "success": false, "message": "Missing required parameters" }` (400) - `{ "success": false, "message": "Token is required" }` (400) - `{ "success": false, "message": "Invalid or inactive token" }` (400) - `{ "success": false, "message": "This document request has expired" }` (400) - `{ "success": false, "message": "File exceeds maximum size limit of X MB" }` (400) - `{ "success": false, "message": "File type not allowed for security reasons" }` (400) - `{ "success": false, "message": "File type 'ext' is not allowed. Allowed types: ..." }` (400) - `{ "success": false, "message": "File type does not match content" }` (400) #### Step 2: Upload File to GCP - **Method:** `PUT` - **URL:** Use the `signedUrl` from Step 1 - **Content-Type:** Use the `contentType` from Step 1 - **Body:** Raw file data - **Response:** HTTP 200 on success #### Step 3: Process Upload - **Endpoint:** `POST /api/upload_document_request_file.php` - **Content-Type:** `application/json` - **Body (JSON):** ``` { "tempBucketPath": "user_uploads/uuid/document.pdf", "filename": "document.pdf", "contentType": "application/pdf", "fileSize": 1024000, "uuid": "12345678-1234-1234-1234-123456789012", "uploadToken": "base64encodedtoken", "access_token": "abc123def456" } ``` - **Response:** ``` { "success": true, "file_id": "docreq_temp_1234567890", "message": "File uploaded and scanned successfully", "scan_result": { "rating": 0, "risk": "Clean", "uuid": "12345678-1234-1234-1234-123456789012", "access_uuid": "access_1234567890", "scan_id": 12345 } } ``` - **Error Responses:** - `{ "success": false, "message": "Missing required parameters" }` - `{ "success": false, "message": "Invalid upload token" }` - `{ "success": false, "message": "File not found in temp bucket" }` - `{ "success": false, "message": "File content does not match file type" }` - `{ "success": false, "message": "Invalid or inactive token" }` - `{ "success": false, "message": "This document request has expired" }` - `{ "success": false, "message": "File exceeds maximum size limit of X MB" }` - `{ "success": false, "message": "File type not allowed for security reasons" }` ### Get Submission Details - **Endpoint:** `GET /api/get_submission_details.php?submission_id=123` - **Authentication:** Required (account owner only) - **Response:** ``` { "success": true, "html": "
...
" } ``` - **Note:** Returns HTML content for displaying submission details including files, submitter info, and scan results --- ## User Profile & Account Management ### Get User Profile - **Endpoint:** `GET /api/get_profile.php` - **Authentication:** Required - **Response:** ``` { "success": true, "profile": { "account_id": 123, "email": "user@example.com", "access_level": "premium", "mfa_enabled": true, "email_verified": true, "is_company_admin": false, "is_stripe_payer": true, "created_at": "2024-01-01 10:00:00", "last_login": "2024-01-15 14:30:00", "company": { "company_id": 5, "company_name": "Acme Corp" }, "subscription": { "stripe_subscription_id": "sub_123" }, "usage": { "messages_sent_this_month": 15, "messages_remaining": 85, "messages_limit": 100, "data_sent_mb": 25.5, "data_received_mb": 10.2, "data_limit_mb": 1000 }, "limits": { "max_attachment_size_mb": 50, "max_attachments": 10, "max_recipients": 25 } } } ``` ### Update User Profile - **Endpoint:** `POST /api/update_profile.php` - **Authentication:** Required - **Body (JSON):** ``` { "email": "newemail@example.com", "current_password": "oldpassword", "new_password": "newpassword", "mfa_enabled": true } ``` - **Response:** `{ "success": true, "message": "Profile updated successfully" }` ### Get Usage Statistics - **Endpoint:** `GET /api/get_usage_stats.php` - **Authentication:** Required - **Response:** ``` { "success": true, "usage_stats": { "current_month": { "messages_sent": 15, "messages_limit": 100, "messages_remaining": 85, "data_sent_mb": 25.5, "data_received_mb": 10.2, "data_limit_mb": 1000, "data_remaining_mb": 989.8 }, "limits": { "max_attachment_size_mb": 50, "max_attachments": 10, "max_recipients": 25 }, "access_level": "premium", "historical_data": [ { "month": "2024-01", "messages_sent": 15, "data_sent_mb": 25.5 } ], "document_requests": { "total_requests": 5, "active_requests": 3, "expired_requests": 2 }, "submissions": { "total_submissions": 12, "submissions_last_30_days": 8 } } } ``` --- ## Document Request Management ### List Document Requests - **Endpoint:** `GET /api/list_document_requests.php` - **Authentication:** Required - **Query Parameters:** `limit`, `offset`, `status` (active/expired/all) - **Response:** ``` { "success": true, "requests": [ { "request_id": 123, "request_name": "Contract Documents", "description": "Please upload signed contracts", "access_token": "abc123def456", "is_active": true, "allow_multiple_submissions": true, "max_file_size_mb": 50, "max_files_per_submission": 10, "allowed_file_types": "pdf,doc,docx", "require_email": true, "require_subject": false, "require_message": true, "expiry_date": "2024-02-15 10:30:00", "expiry_status": "active", "created_at": "2024-01-16 10:30:00", "submission_count": 5, "last_submission": "2024-01-20 15:45:00", "upload_url": "../document_request_upload.php?token=abc123def456" } ], "pagination": { "total": 5, "limit": 20, "offset": 0, "has_more": false } } ``` ### Update Document Request - **Endpoint:** `POST /api/update_document_request.php` - **Authentication:** Required - **Body (JSON):** ``` { "request_id": 123, "request_name": "Updated Contract Documents", "description": "Updated description", "is_active": true, "max_file_size_mb": 100, "expiry_days": 60 } ``` - **Response:** `{ "success": true, "message": "Document request updated successfully", "request": {...} }` ### Delete Document Request - **Endpoint:** `POST /api/delete_document_request.php` - **Authentication:** Required - **Body (JSON):** ``` { "request_id": 123, "force_delete": false } ``` - **Response:** `{ "success": true, "message": "Document request deleted successfully", "submissions_deleted": 5, "files_deleted": 12 }` --- ## Admin & Enterprise Management ### Admin List Users - **Endpoint:** `GET /api/admin/list_users.php` - **Authentication:** Required (Admin only) - **Query Parameters:** `limit`, `offset`, `access_level`, `company_id`, `search` - **Response:** ``` { "success": true, "users": [ { "account_id": 123, "email": "user@example.com", "access_level": "premium", "is_company_admin": false, "is_stripe_payer": true, "email_verified": true, "mfa_enabled": true, "account_locked": false, "last_login": "2024-01-15 14:30:00", "failed_login_attempts": 0, "created_at": "2024-01-01 10:00:00", "company": { "company_id": 5, "company_name": "Acme Corp" } } ], "pagination": { "total": 150, "limit": 20, "offset": 0, "has_more": true } } ``` ### Admin Update User - **Endpoint:** `POST /api/admin/update_user.php` - **Authentication:** Required (Admin only) - **Body (JSON):** ``` { "account_id": 123, "access_level": "enterprise", "is_company_admin": true, "account_locked": false, "company_id": 5 } ``` - **Response:** `{ "success": true, "message": "User updated successfully", "user": {...} }` ### Admin Get Security Logs - **Endpoint:** `GET /api/admin/get_security_logs.php` - **Authentication:** Required (Admin only) - **Query Parameters:** `limit`, `offset`, `log_type` (auth/activity/malware), `start_date`, `end_date`, `ip_address` - **Response:** ``` { "success": true, "logs": [ { "log_type": "authentication", "log_id": 123, "account_id": 456, "email": "user@example.com", "access_level": "premium", "ip_address": "192.168.1.1", "user_agent": "Mozilla/5.0...", "login_time": "2024-01-15 14:30:00", "status": "success", "login_successful": true } ], "pagination": { "total": 1000, "limit": 50, "offset": 0, "has_more": true } } ``` ### Admin Get Malware Detections - **Endpoint:** `GET /api/admin/get_malware_detections.php` - **Authentication:** Required (Admin only) - **Query Parameters:** `limit`, `offset`, `rating` (0/1/2), `start_date`, `end_date`, `sender_id` - **Response:** ``` { "success": true, "detections": [ { "detection_id": 123, "sender_id": 456, "sender_email": "user@example.com", "account_email": "user@example.com", "access_level": "premium", "file_name": "document.pdf", "file_path": "/path/to/file", "file_size": 1024000, "scan_uuid": "scan_123456", "scan_rating": 0, "scan_risk": "Clean", "detection_timestamp": "2024-01-15 14:30:00", "risk_level": "clean" } ], "summary": { "total_detections": 1000, "clean_files": 950, "suspicious_files": 40, "malicious_files": 10, "detections_last_7_days": 25, "detections_last_30_days": 100 }, "pagination": { "total": 1000, "limit": 50, "offset": 0, "has_more": true } } ``` --- ## Advanced Features ### Archive Message - **Endpoint:** `POST /api/archive_message.php` - **Authentication:** Required - **Body (JSON):** ``` { "message_id": 123, "archive": true } ``` - **Response:** `{ "success": true, "message": "Message archived successfully", "message_id": 123, "archived": true }` ### Get File Metadata - **Endpoint:** `GET /api/get_file_metadata.php?file_id=123` - **Authentication:** Required - **Response:** ``` { "success": true, "file": { "file_id": 123, "message_id": 456, "file_name": "document.pdf", "file_path": "/path/to/file", "file_size": 1024000, "mime_type": "application/pdf", "file_extension": "pdf", "file_type": "document", "file_icon": "file-pdf", "storage_location": "cloud", "preview_only": false, "scan_rating": 0, "scan_risk": "Clean", "scan_uuid": "scan_123456", "access_uuid": "access_123456", "scan_id": 789, "scan_timestamp": "2024-01-15 14:30:00", "message": { "message_id": 456, "subject": "Important Document", "message_text": "Please review this document", "created_at": "2024-01-15 10:00:00", "sender_email": "sender@example.com" }, "statistics": { "download_count": 5, "view_count": 12, "total_accesses": 17 }, "recent_activity": [...] } } ``` ### Bulk Operations - **Endpoint:** `POST /api/bulk_operations.php` - **Authentication:** Required - **Body (JSON):** ``` { "operation": "archive_messages", "targets": [123, 456, 789] } ``` - **Valid Operations:** `archive_messages`, `unarchive_messages`, `delete_messages`, `delete_document_requests` - **Response:** ``` { "success": true, "operation": "archive_messages", "summary": { "total_processed": 3, "successful": 3, "failed": 0 }, "results": [ { "id": 123, "status": "archived" }, { "id": 456, "status": "archived" }, { "id": 789, "status": "archived" } ], "errors": [] } ``` ### Get System Status - **Endpoint:** `GET /api/get_system_status.php` - **Authentication:** Required (Admin gets detailed info) - **Response:** ``` { "success": true, "system_status": { "timestamp": "2024-01-15 14:30:00", "status": "operational", "basic": { "api_version": "1.0", "server_time": "2024-01-15 14:30:00", "timezone": "UTC" }, "database": { "status": "connected", "driver": "mysql" }, "user": { "account_id": 123, "access_level": "premium", "limits": { "max_attachment_size_mb": 50, "max_attachments": 10 } }, "admin": { "database_stats": { "total_users": 1500, "total_messages": 50000, "total_files": 25000, "total_document_requests": 500, "total_storage_bytes": 1073741824, "total_storage_mb": 1024 }, "recent_activity": { "logins_last_24h": 150, "messages_last_24h": 500, "malware_detections_last_24h": 5 }, "health_checks": { "disk_space": { "status": "ok", "free_gb": 50.5 }, "security": { "status": "ok", "failed_logins_last_hour": 2 } } } } } ``` --- ## Authentication & Authorization - Most endpoints require the user to be authenticated (session-based, via login/register endpoints). - Only authorized users (sender or recipient) can access, modify, or delete messages, attachments, and replies. - **Exception:** Document request file uploads (`/api/upload_document_request_file.php`) use token-based authentication and do not require a user account. - **Admin Endpoints:** Require admin access level for full system management capabilities. --- ## Error Handling - All errors are returned as JSON: `{ "error": "Error message" }` - HTTP status codes are set appropriately (400, 401, 403, 404, 405, 500) --- ## Example Usage ### Basic API Usage - Use tools like Postman or curl to interact with the API - For JSON requests, set `Content-Type: application/json` - For form data, set `Content-Type: application/x-www-form-urlencoded` ### File Upload Example (JavaScript) ```javascript // Step 1: Get signed URL const response = await fetch('/get_signed_url.php', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ filename: file.name, contentType: file.type, fileSize: file.size }) }); const { signedUrl, tempBucketPath, uuid, uploadToken } = await response.json(); // Step 2: Upload file directly to GCP await fetch(signedUrl, { method: 'PUT', body: file }); // Step 3: Process upload const processResponse = await fetch('/process_cloud_upload.php', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ tempBucketPath, filename: file.name, contentType: file.type, fileSize: file.size, uuid, uploadToken }) }); const { file_id } = await processResponse.json(); // Step 4: Use file_id in message sending await fetch('/api/send_message.php', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: new URLSearchParams({ recipient: 'user@example.com', subject: 'Test Message', body: 'Here is the document', uploaded_file_ids: file_id }) }); ``` ### Document Request Upload Example (JavaScript) ```javascript // Step 1: Get signed URL for document request const response = await fetch('/api/get_document_request_signed_url.php', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ filename: file.name, contentType: file.type || 'application/octet-stream', fileSize: file.size, access_token: 'abc123def456' // Document request access token }) }); const data = await response.json(); if (!data.success) { throw new Error(data.message || 'Failed to get upload URL'); } const { signedUrl, tempBucketPath, uuid, uploadToken } = data; // Step 2: Upload file directly to GCP const uploadResponse = await fetch(signedUrl, { method: 'PUT', headers: { 'Content-Type': file.type || 'application/octet-stream' }, body: file }); if (!uploadResponse.ok) { throw new Error(`Upload failed with status: ${uploadResponse.status}`); } // Step 3: Process upload and trigger malware scan const processResponse = await fetch('/api/upload_document_request_file.php', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ tempBucketPath, filename: file.name, contentType: file.type || 'application/octet-stream', fileSize: file.size, uuid, uploadToken, access_token: 'abc123def456' // Document request access token }) }); const result = await processResponse.json(); if (!result.success) { throw new Error(result.message || 'Upload processing failed'); } const { file_id, scan_result } = result; // file_id can be used in form submission // scan_result contains: { rating, risk, uuid, access_uuid, scan_id } ``` --- For more information, contact support at [GetSafeDocs](contact.php).