Skip to main content

Delete User File

Remove a specific file from user’s private subchat:
DELETE /v1/me/chats/files/{file_id}

Delete Example

curl -X DELETE https://api.trainlyai.com/v1/me/chats/files/v1_user_xyz_document.pdf_1609459200 \
  -H "Authorization: Bearer <USER_OAUTH_ID_TOKEN>" \
  -H "X-App-ID: app_your_app_id"
Response:
{
  "success": true,
  "message": "File 'document.pdf' deleted successfully",
  "file_id": "v1_user_xyz_document.pdf_1609459200",
  "filename": "document.pdf",
  "chunks_deleted": 42,
  "size_bytes_freed": 524288
}

Remove Document Context

Remove a document from a chat (internal endpoint):
DELETE /remove_context/{file_id}

Remove Context Example

curl -X DELETE https://api.trainlyai.com/remove_context/doc_abc123 \
  -H "Authorization: Bearer your_api_key"
Response:
{
  "status": "success",
  "message": "Document doc_abc123 and its chunks deleted",
  "nodes_deleted": 43
}
This action is permanent and cannot be undone. All embeddings and chunks will be deleted.

Delete All Chat Data

Remove all documents and nodes from a chat:
DELETE /delete_chat_nodes/{chat_id}

Delete Chat Nodes Example

curl -X DELETE https://api.trainlyai.com/delete_chat_nodes/chat_abc123 \
  -H "Authorization: Bearer your_api_key"
Response:
{
  "status": "success",
  "message": "All nodes for chat chat_abc123 deleted",
  "nodes_deleted": 256,
  "relationships_deleted": 512
}

Cleanup Chat Cluster

Advanced cleanup including parent and child chats:
POST /cleanup_chat_data/{chat_id}

Cleanup with Subchats

curl -X POST "https://api.trainlyai.com/cleanup_chat_data/chat_abc123?child_chat_ids=subchat1,subchat2" \
  -H "Authorization: Bearer your_api_key"
Query Parameters:
  • convex_id (optional): Alternative chat ID
  • child_chat_ids (optional): Comma-separated child chat IDs
Response:
{
  "status": "success",
  "message": "Chat cluster chat_abc123 and 2 child chats deleted from Neo4j",
  "nodes_deleted": 512,
  "relationships_deleted": 1024,
  "debug_info": {
    "parent_chat_id": "chat_abc123",
    "child_chat_ids": ["subchat1", "subchat2"],
    "total_chat_ids_processed": 3,
    "documents_found_before_deletion": 15
  }
}

JavaScript Examples

Delete with Confirmation

async function deleteFile(fileId, userToken, appId) {
  // Confirm with user first
  const confirmed = confirm(
    "Are you sure you want to delete this file? This cannot be undone.",
  );

  if (!confirmed) {
    return { cancelled: true };
  }

  try {
    const response = await fetch(
      `https://api.trainlyai.com/v1/me/chats/files/${fileId}`,
      {
        method: "DELETE",
        headers: {
          Authorization: `Bearer ${userToken}`,
          "X-App-ID": appId,
        },
      },
    );

    if (!response.ok) {
      throw new Error(`Delete failed: ${response.status}`);
    }

    const result = await response.json();

    return {
      success: true,
      message: `File deleted successfully. Freed ${formatBytes(result.size_bytes_freed)}`,
      data: result,
    };
  } catch (error) {
    return {
      success: false,
      error: error.message,
    };
  }
}

function formatBytes(bytes) {
  if (bytes === 0) return "0 Bytes";
  const k = 1024;
  const sizes = ["Bytes", "KB", "MB", "GB"];
  const i = Math.floor(Math.log(bytes) / Math.log(k));
  return Math.round((bytes / Math.pow(k, i)) * 100) / 100 + " " + sizes[i];
}

// Usage
const result = await deleteFile("v1_user_xyz_doc_123", userToken, appId);
if (result.success) {
  console.log(result.message);
} else if (result.cancelled) {
  console.log("Deletion cancelled");
} else {
  console.error("Delete failed:", result.error);
}

Bulk Delete

async function bulkDeleteFiles(fileIds, userToken, appId) {
  const results = {
    successful: [],
    failed: [],
  };

  for (const fileId of fileIds) {
    try {
      const response = await fetch(
        `https://api.trainlyai.com/v1/me/chats/files/${fileId}`,
        {
          method: "DELETE",
          headers: {
            Authorization: `Bearer ${userToken}`,
            "X-App-ID": appId,
          },
        },
      );

      if (response.ok) {
        const data = await response.json();
        results.successful.push({
          fileId,
          filename: data.filename,
          spaceFree: data.size_bytes_freed,
        });
      } else {
        results.failed.push({
          fileId,
          error: `HTTP ${response.status}`,
        });
      }
    } catch (error) {
      results.failed.push({
        fileId,
        error: error.message,
      });
    }

    // Add small delay to avoid rate limiting
    await new Promise((resolve) => setTimeout(resolve, 100));
  }

  return results;
}

// Usage
const fileIds = ["file1", "file2", "file3"];
const results = await bulkDeleteFiles(fileIds, userToken, appId);
console.log(`Deleted ${results.successful.length} files`);
console.log(`Failed to delete ${results.failed.length} files`);

Delete with Undo

class FileManager {
  constructor(userToken, appId) {
    this.userToken = userToken;
    this.appId = appId;
    this.deletedFiles = [];
  }

  async deleteFile(fileId) {
    const response = await fetch(
      `https://api.trainlyai.com/v1/me/chats/files/${fileId}`,
      {
        method: "DELETE",
        headers: {
          Authorization: `Bearer ${this.userToken}`,
          "X-App-ID": this.appId,
        },
      },
    );

    if (!response.ok) {
      throw new Error(`Delete failed: ${response.status}`);
    }

    const result = await response.json();

    // Store for potential undo (temporary - not actually restorable)
    this.deletedFiles.push({
      fileId,
      filename: result.filename,
      deletedAt: Date.now(),
    });

    return result;
  }

  getRecentlyDeleted(withinMinutes = 5) {
    const cutoff = Date.now() - withinMinutes * 60 * 1000;
    return this.deletedFiles.filter((f) => f.deletedAt > cutoff);
  }

  clearDeleteHistory() {
    this.deletedFiles = [];
  }
}

// Usage
const manager = new FileManager(userToken, appId);
await manager.deleteFile("file_123");

// Show recently deleted
console.log("Recently deleted:", manager.getRecentlyDeleted());

React Component Example

import { useState } from "react";

function FileList({ files, userToken, appId, onFileDeleted }) {
  const [deleting, setDeleting] = useState(null);

  const handleDelete = async (fileId, filename) => {
    if (!confirm(`Delete "${filename}"? This cannot be undone.`)) {
      return;
    }

    setDeleting(fileId);

    try {
      const response = await fetch(
        `https://api.trainlyai.com/v1/me/chats/files/${fileId}`,
        {
          method: "DELETE",
          headers: {
            Authorization: `Bearer ${userToken}`,
            "X-App-ID": appId,
          },
        },
      );

      if (!response.ok) {
        throw new Error("Delete failed");
      }

      const result = await response.json();

      // Notify parent component
      onFileDeleted(fileId, result);

      // Show success message
      alert(
        `File deleted successfully. Freed ${formatBytes(result.size_bytes_freed)}`,
      );
    } catch (error) {
      alert(`Failed to delete file: ${error.message}`);
    } finally {
      setDeleting(null);
    }
  };

  return (
    <div className="file-list">
      {files.map((file) => (
        <div key={file.file_id} className="file-item">
          <span>{file.filename}</span>
          <button
            onClick={() => handleDelete(file.file_id, file.filename)}
            disabled={deleting === file.file_id}
          >
            {deleting === file.file_id ? "Deleting..." : "Delete"}
          </button>
        </div>
      ))}
    </div>
  );
}

function formatBytes(bytes) {
  // ... same as before
}

Debug Before Delete

Before deleting, inspect what will be removed:
GET /debug_chat_data/{chat_id}

Debug Example

curl -X GET https://api.trainlyai.com/debug_chat_data/chat_abc123
Response:
{
  "chat_id": "chat_abc123",
  "search_prefix": "subchat_chat_abc123_",
  "documents_found": 3,
  "total_chunks": 127,
  "documents": [
    {
      "chatId": "chat_abc123",
      "docId": "doc1",
      "filename": "research.pdf",
      "chunk_count": 42
    },
    {
      "chatId": "subchat_chat_abc123_user1",
      "docId": "doc2",
      "filename": "notes.txt",
      "chunk_count": 85
    }
  ]
}

Best Practices

1

Always Confirm

Require user confirmation before deleting files
2

Show Impact

Display what will be deleted (file size, chunk count)
3

Log Deletions

Keep audit logs of deletion events
4

Graceful Errors

Handle 404 errors (file already deleted) gracefully
5

Batch Operations

Add delays between bulk deletions to avoid rate limits

Error Handling

Common Delete Errors

try {
  await deleteFile(fileId);
} catch (error) {
  if (error.status === 404) {
    console.log("File already deleted or not found");
  } else if (error.status === 401) {
    console.error("Unauthorized - check your credentials");
  } else if (error.status === 403) {
    console.error("Forbidden - you don't have permission to delete this file");
  } else if (error.status === 429) {
    console.error("Rate limited - please wait before retrying");
  } else {
    console.error("Delete failed:", error.message);
  }
}

Analytics Impact

Deletions automatically update analytics:
  • Storage space is freed immediately
  • File count decreases
  • Analytics events are logged
  • Parent app/workspace stats are updated
{
  "event": "file_deleted",
  "app_id": "app_abc123",
  "user_id": "user_xyz789",
  "filename": "document.pdf",
  "size_freed": 524288,
  "chunks_removed": 42,
  "timestamp": 1609459200000
}