6 min read

Delete Document

Permanently delete a document and all associated data

Permanently delete a document and all its associated data including the original file, extracted data, and metadata.

DELETE/v1/documents/:id

Overview

Use this endpoint to:

  • Remove sensitive documents after processing
  • Clean up failed or test documents
  • Comply with data retention policies
  • Free up storage (for enterprise plans)
⚠️

Permanent Deletion

This action is irreversible. Once deleted, the document and all its data cannot be recovered. Credits used for processing are not refunded.

Request

Headers

ParameterTypeDescription
X-API-Keyrequired
stringYour DocuRift API key (format: frc_xxxxx)

Path Parameters

ParameterTypeDescription
idrequired
stringDocument ID to delete (format: doc_xxxxx)

Code Examples

cURL

curl
curl -X DELETE "https://api.docurift.com/v1/documents/doc_abc123xyz456" \
-H "X-API-Key: frc_your_api_key_here"

Python

delete_document.py
import requests
import os

API_KEY = os.getenv('DOCURIFT_API_KEY')
API_URL = 'https://api.docurift.com/v1'

def delete_document(document_id):
  """Delete a document permanently."""
  headers = {
      'X-API-Key': API_KEY
  }

  response = requests.delete(
      f'{API_URL}/documents/{document_id}',
      headers=headers
  )

  response.raise_for_status()
  return response.json()

# Example usage
result = delete_document('doc_abc123xyz456')

if result['success']:
  print(f"Document deleted successfully")
  print(f"Deleted at: {result['data']['deletedAt']}")

JavaScript

deleteDocument.js
const API_KEY = process.env.DOCURIFT_API_KEY;
const API_URL = 'https://api.docurift.com/v1';

async function deleteDocument(documentId) {
const response = await fetch(`${API_URL}/documents/${documentId}`, {
  method: 'DELETE',
  headers: {
    'X-API-Key': API_KEY
  }
});

if (!response.ok) {
  const error = await response.json();
  throw new Error(error.error.message);
}

return response.json();
}

// Example usage
try {
const result = await deleteDocument('doc_abc123xyz456');
console.log('Document deleted:', result.data.id);
console.log('Deleted at:', result.data.deletedAt);
} catch (error) {
console.error('Failed to delete:', error.message);
}

Batch Delete (Python)

batch_delete.py
import requests
import os
from concurrent.futures import ThreadPoolExecutor, as_completed

API_KEY = os.getenv('DOCURIFT_API_KEY')
API_URL = 'https://api.docurift.com/v1'

def delete_document(document_id):
  """Delete a single document."""
  headers = {'X-API-Key': API_KEY}
  response = requests.delete(f'{API_URL}/documents/{document_id}', headers=headers)
  response.raise_for_status()
  return document_id

def batch_delete_documents(document_ids, max_workers=5):
  """
  Delete multiple documents in parallel.

  Args:
      document_ids: List of document IDs to delete
      max_workers: Maximum concurrent deletions

  Returns:
      dict with successful and failed deletions
  """
  results = {'deleted': [], 'failed': []}

  with ThreadPoolExecutor(max_workers=max_workers) as executor:
      future_to_id = {
          executor.submit(delete_document, doc_id): doc_id
          for doc_id in document_ids
      }

      for future in as_completed(future_to_id):
          doc_id = future_to_id[future]
          try:
              future.result()
              results['deleted'].append(doc_id)
          except Exception as e:
              results['failed'].append({'id': doc_id, 'error': str(e)})

  return results

# Example: Delete all failed documents
def delete_failed_documents():
  """Delete all documents with failed status."""
  headers = {'X-API-Key': API_KEY}

  # Get all failed documents
  response = requests.get(
      f'{API_URL}/documents?status=failed&limit=100',
      headers=headers
  )
  response.raise_for_status()

  failed_docs = response.json()['data']['documents']
  doc_ids = [doc['id'] for doc in failed_docs]

  if doc_ids:
      results = batch_delete_documents(doc_ids)
      print(f"Deleted {len(results['deleted'])} documents")
      if results['failed']:
          print(f"Failed to delete {len(results['failed'])} documents")
  else:
      print("No failed documents to delete")

Response

Success Response (200 OK)

response.json
{
"success": true,
"data": {
  "id": "doc_abc123xyz456",
  "deleted": true,
  "deletedAt": "2024-01-26T12:00:00Z"
},
"message": "Document and all associated data have been permanently deleted"
}

Response Fields

ParameterTypeDescription
id
stringID of the deleted document
deleted
booleanConfirmation of deletion (always true on success)
deletedAt
stringISO 8601 timestamp of deletion

Error Responses

401 Unauthorized

error_401.json
{
"success": false,
"error": {
  "code": "INVALID_API_KEY",
  "message": "Invalid API key"
}
}

403 Forbidden

error_403.json
{
"success": false,
"error": {
  "code": "FORBIDDEN",
  "message": "You do not have permission to delete this document"
}
}

404 Not Found

error_404.json
{
"success": false,
"error": {
  "code": "DOCUMENT_NOT_FOUND",
  "message": "Document with ID 'doc_abc123xyz456' not found"
}
}

409 Conflict

error_409.json
{
"success": false,
"error": {
  "code": "DOCUMENT_PROCESSING",
  "message": "Cannot delete document while it is being processed. Wait for processing to complete or cancel first."
}
}

Error Codes Reference

| Code | HTTP Status | Description | Solution | |------|-------------|-------------|----------| | INVALID_API_KEY | 401 | API key invalid or expired | Verify API key | | FORBIDDEN | 403 | No permission to delete | Check organization access | | DOCUMENT_NOT_FOUND | 404 | Document does not exist | Verify document ID | | DOCUMENT_PROCESSING | 409 | Document is being processed | Wait for completion |

Best Practices

Confirm Before Deletion

Always verify the document before deletion in production:

confirm_delete.py
def safe_delete_document(document_id, confirm=True):
  """Delete with confirmation."""
  # First, get the document to verify
  headers = {'X-API-Key': API_KEY}
  response = requests.get(f'{API_URL}/documents/{document_id}', headers=headers)

  if response.status_code == 404:
      print(f"Document {document_id} not found")
      return None

  doc = response.json()['data']

  if confirm:
      print(f"About to delete:")
      print(f"  ID: {doc['id']}")
      print(f"  File: {doc['fileName']}")
      print(f"  Type: {doc['documentType']}")
      print(f"  Status: {doc['status']}")

      confirmation = input("Type 'DELETE' to confirm: ")
      if confirmation != 'DELETE':
          print("Deletion cancelled")
          return None

  return delete_document(document_id)

Implement Soft Delete Pattern

For applications requiring undo functionality, implement soft delete:

soft_delete.js
// Store deleted document IDs with metadata before deletion
const deletedDocuments = new Map();
const RETENTION_PERIOD = 30 * 24 * 60 * 60 * 1000; // 30 days

async function softDelete(documentId) {
// Get document data first
const doc = await getDocument(documentId);

// Store in soft delete registry
deletedDocuments.set(documentId, {
  metadata: doc.data,
  deletedAt: new Date(),
  expiresAt: new Date(Date.now() + RETENTION_PERIOD)
});

// Actually delete from DocuRift
await deleteDocument(documentId);

console.log(`Document ${documentId} soft-deleted. Metadata retained for 30 days.`);
}

// Clean up expired soft-deleted records
function cleanupExpired() {
const now = Date.now();
for (const [id, data] of deletedDocuments) {
  if (data.expiresAt < now) {
    deletedDocuments.delete(id);
  }
}
}

Audit Logging

Log all delete operations for compliance:

audit_delete.py
import logging
from datetime import datetime

# Configure audit logger
audit_logger = logging.getLogger('docurift.audit')
audit_logger.setLevel(logging.INFO)

def audited_delete(document_id, user_id, reason=None):
  """Delete with audit logging."""
  # Log before deletion
  audit_logger.info(
      f"DELETE_INITIATED | doc_id={document_id} | user={user_id} | reason={reason}"
  )

  try:
      result = delete_document(document_id)

      audit_logger.info(
          f"DELETE_SUCCESS | doc_id={document_id} | user={user_id} | "
          f"deleted_at={result['data']['deletedAt']}"
      )

      return result

  except Exception as e:
      audit_logger.error(
          f"DELETE_FAILED | doc_id={document_id} | user={user_id} | error={str(e)}"
      )
      raise

Data Retention Policy

Implement automated cleanup based on retention policy:

retention_cleanup.py
from datetime import datetime, timedelta

def cleanup_old_documents(retention_days=90, dry_run=True):
  """
  Delete documents older than retention period.

  Args:
      retention_days: Number of days to retain documents
      dry_run: If True, only report what would be deleted
  """
  cutoff_date = datetime.utcnow() - timedelta(days=retention_days)

  # Get old documents
  result = list_documents(
      end_date=cutoff_date.isoformat() + 'Z',
      status='completed',
      limit=100
  )

  documents = result['data']['documents']

  if dry_run:
      print(f"[DRY RUN] Would delete {len(documents)} documents:")
      for doc in documents:
          print(f"  - {doc['id']}: {doc['fileName']} ({doc['createdAt']})")
      return

  # Delete old documents
  deleted_count = 0
  for doc in documents:
      try:
          delete_document(doc['id'])
          deleted_count += 1
      except Exception as e:
          print(f"Failed to delete {doc['id']}: {e}")

  print(f"Deleted {deleted_count} documents older than {retention_days} days")
💡

Credits

Deleting a document does not refund the credits used for processing. Credits are consumed at the time of processing.

⚠️

Processing Documents

You cannot delete a document that is currently being processed. Wait for processing to complete or fail before attempting deletion.