📚 API Documentation

v1.0

🚀 Getting Started

Doc-Crafter API allows you to generate thousands of personalized documents from DOCX templates and CSV/Excel data files. This guide will walk you through the complete process.

Base URL: https://doc-crafter.medevtech.net

What You'll Need

📋 Step 1: Get Your API Key

1 Access Admin Dashboard

Navigate to the Admin Dashboard at: https://doc-crafter.medevtech.net/admin

2 Login

Login with your admin credentials. If you don't have an account, contact your system administrator.

3 Navigate to API Keys

Go to the "API Keys" section in the sidebar menu.

4 Create New API Key

Click "Create New API Key" and fill in the required information:

  • Name: Descriptive name (e.g., "Mobile App")
  • Slug: Unique identifier (e.g., "mobile_app")
  • Role: Select appropriate role with permissions
  • Description: Optional description
  • Expiration: Optional expiration date
⚠️ Important: The API key is shown only once when created. Make sure to copy and save it securely. You won't be able to see it again. If you lose it, you'll need to rotate or create a new key.
5 Save Your API Key

Store your API key securely. You'll use it in the X-API-Key header for all API requests.

🔌 Step 2: Understanding the API Endpoint

POST /generator

Request Requirements

Field Type Required Description
template File (DOCX) ✅ Yes DOCX template with placeholders like {field_name}
data File (CSV/Excel) ✅ Yes CSV or Excel file with data rows
output_format String ❌ No "docx" (default) or "pdf"

Headers

Header Value Required
X-API-Key Your API key ✅ Yes
Content-Type multipart/form-data ✅ Yes

Response

✅ Success (200 OK): Binary file stream (DOCX or PDF) with headers:
  • Content-Type: application/pdf or application/vnd.openxmlformats-officedocument.wordprocessingml.document
  • Content-Disposition: attachment; filename="generated_{timestamp}.{format}"

Error Responses

Status Code Error Description
400 Bad Request Invalid files or format
401 Unauthorized Missing or invalid API key
403 Forbidden Insufficient permissions or expired key
413 Payload Too Large File size exceeds limit (25MB template, 50MB data)
500 Internal Server Error Server error during processing

💻 Step 3: Implementation Examples

Using cURL

Bash
curl -X POST https://doc-crafter.medevtech.net/generator \
  -H "X-API-Key: your-api-key-here" \
  -F "template=@invoice_template.docx" \
  -F "data=@clients.csv" \
  -F "output_format=pdf" \
  --output invoices.pdf

# For DOCX output (default):
curl -X POST https://doc-crafter.medevtech.net/generator \
  -H "X-API-Key: your-api-key-here" \
  -F "template=@template.docx" \
  -F "data=@data.csv" \
  --output documents.docx
💡 Tip: Replace your-api-key-here with your actual API key. Make sure the file paths are correct relative to your current directory.

Using Node.js (Native)

JavaScript
const fs = require('fs');
const FormData = require('form-data');
const https = require('https');

// Create form data
const form = new FormData();
form.append('template', fs.createReadStream('./template.docx'));
form.append('data', fs.createReadStream('./data.csv'));
form.append('output_format', 'pdf');

// Make request
const options = {
  hostname: 'doc-crafter.medevtech.net',
  path: '/generator',
  method: 'POST',
  headers: {
    'X-API-Key': 'your-api-key-here',
    ...form.getHeaders()
  }
};

const req = https.request(options, (res) => {
  if (res.statusCode !== 200) {
    console.error('Error:', res.statusCode);
    res.pipe(process.stderr);
    return;
  }

  // Save the file
  const fileStream = fs.createWriteStream('./output.pdf');
  res.pipe(fileStream);
  
  fileStream.on('finish', () => {
    console.log('✅ File saved successfully!');
  });
});

req.on('error', (error) => {
  console.error('Request error:', error);
});

form.pipe(req);
📦 Install: npm install form-data

Using Express.js (Backend)

JavaScript
const express = require('express');
const multer = require('multer');
const FormData = require('form-data');
const axios = require('axios');
const fs = require('fs');

const app = express();
const upload = multer({ dest: 'uploads/' });

// Endpoint to handle file upload and forward to Doc-Crafter
app.post('/generate-document', upload.fields([
  { name: 'template', maxCount: 1 },
  { name: 'data', maxCount: 1 }
]), async (req, res) => {
  try {
    const { output_format = 'docx' } = req.body;
    const templateFile = req.files.template[0];
    const dataFile = req.files.data[0];

    // Create form data
    const formData = new FormData();
    formData.append('template', fs.createReadStream(templateFile.path), {
      filename: templateFile.originalname,
      contentType: templateFile.mimetype
    });
    formData.append('data', fs.createReadStream(dataFile.path), {
      filename: dataFile.originalname,
      contentType: dataFile.mimetype
    });
    formData.append('output_format', output_format);

    // Forward to Doc-Crafter API
    const response = await axios.post(
      'https://doc-crafter.medevtech.net/generator',
      formData,
      {
        headers: {
          'X-API-Key': process.env.DOC_CRAFTER_API_KEY, // Store in .env
          ...formData.getHeaders()
        },
        responseType: 'stream'
      }
    );

    // Set response headers
    res.setHeader('Content-Type', response.headers['content-type']);
    res.setHeader('Content-Disposition', response.headers['content-disposition']);

    // Pipe the response to client
    response.data.pipe(res);

    // Cleanup uploaded files
    fs.unlinkSync(templateFile.path);
    fs.unlinkSync(dataFile.path);

  } catch (error) {
    console.error('Error:', error.response?.data || error.message);
    res.status(error.response?.status || 500).json({
      error: error.response?.data?.message || 'Generation failed'
    });
  }
});

app.listen(3000, () => {
  console.log('Server running on port 3000');
});
📦 Install: npm install express multer form-data axios
⚠️ Environment Variable: Store your API key in .env file: DOC_CRAFTER_API_KEY=your-api-key-here

Using React.js (Frontend)

JavaScript/React
import React, { useState } from 'react';
import axios from 'axios';

function DocumentGenerator() {
  const [templateFile, setTemplateFile] = useState(null);
  const [dataFile, setDataFile] = useState(null);
  const [outputFormat, setOutputFormat] = useState('docx');
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState(null);
  const [success, setSuccess] = useState(false);

  // Store API key (in production, use environment variable or secure storage)
  const API_KEY = 'your-api-key-here';

  const handleGenerate = async () => {
    if (!templateFile || !dataFile) {
      setError('Please select both template and data files');
      return;
    }

    setLoading(true);
    setError(null);
    setSuccess(false);

    try {
      const formData = new FormData();
      formData.append('template', templateFile);
      formData.append('data', dataFile);
      formData.append('output_format', outputFormat);

      const response = await axios.post(
        'https://doc-crafter.medevtech.net/generator',
        formData,
        {
          headers: {
            'X-API-Key': API_KEY,
            'Content-Type': 'multipart/form-data'
          },
          responseType: 'blob' // Important for binary files
        }
      );

      // Create download link
      const url = window.URL.createObjectURL(new Blob([response.data]));
      const link = document.createElement('a');
      link.href = url;
      
      // Get filename from Content-Disposition header
      const contentDisposition = response.headers['content-disposition'];
      const filename = contentDisposition
        ? contentDisposition.split('filename=')[1]?.replace(/"/g, '')
        : `generated.${outputFormat}`;
      
      link.setAttribute('download', filename);
      document.body.appendChild(link);
      link.click();
      link.remove();
      window.URL.revokeObjectURL(url);

      setSuccess(true);
    } catch (err) {
      // Handle error response
      if (err.response) {
        if (err.response.status === 401) {
          setError('Invalid API key. Please check your API key.');
        } else if (err.response.status === 403) {
          setError('Access denied. Your API key may be expired or inactive.');
        } else if (err.response.status === 413) {
          setError('File size too large. Please use smaller files.');
        } else {
          // Try to parse error message
          const reader = new FileReader();
          reader.onload = () => {
            try {
              const errorData = JSON.parse(reader.result);
              setError(errorData.message || 'Generation failed');
            } catch {
              setError('Generation failed. Please try again.');
            }
          };
          reader.readAsText(err.response.data);
        }
      } else {
        setError('Network error. Please check your connection.');
      }
    } finally {
      setLoading(false);
    }
  };

  return (
    <div className="document-generator">
      <h2>Generate Documents</h2>
      
      <div>
        <label>Template File (DOCX):</label>
        <input
          type="file"
          accept=".docx"
          onChange={(e) => setTemplateFile(e.target.files[0])}
        />
      </div>

      <div>
        <label>Data File (CSV/Excel):</label>
        <input
          type="file"
          accept=".csv,.xlsx,.xls"
          onChange={(e) => setDataFile(e.target.files[0])}
        />
      </div>

      <div>
        <label>Output Format:</label>
        <select value={outputFormat} onChange={(e) => setOutputFormat(e.target.value)}>
          <option value="docx">DOCX</option>
          <option value="pdf">PDF</option>
        </select>
      </div>

      <button onClick={handleGenerate} disabled={loading}>
        {loading ? 'Generating...' : 'Generate Document'}
      </button>

      {error && <div className="error">{error}</div>}
      {success && <div className="success">Document generated successfully!</div>}
    </div>
  );
}

export default DocumentGenerator;
📦 Install: npm install axios
⚠️ Security Note: In production, never hardcode API keys in frontend code. Use environment variables or proxy requests through your backend server.

Using Python

Python
import requests
import os

# API Configuration
API_URL = 'https://doc-crafter.medevtech.net/generator'
API_KEY = 'your-api-key-here'  # Store in environment variable

def generate_document(template_path, data_path, output_format='docx', output_path=None):
    """
    Generate document from template and data files.
    
    Args:
        template_path: Path to DOCX template file
        data_path: Path to CSV/Excel data file
        output_format: 'docx' or 'pdf'
        output_path: Path to save output file (optional)
    
    Returns:
        bytes: Generated document as bytes
    """
    try:
        # Prepare files
        with open(template_path, 'rb') as template_file, \
             open(data_path, 'rb') as data_file:
            
            files = {
                'template': (os.path.basename(template_path), template_file, 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'),
                'data': (os.path.basename(data_path), data_file, 'application/vnd.ms-excel')
            }
            
            data = {
                'output_format': output_format
            }
            
            headers = {
                'X-API-Key': API_KEY
            }
            
            # Make request
            response = requests.post(
                API_URL,
                files=files,
                data=data,
                headers=headers,
                timeout=300  # 5 minutes timeout for large files
            )
            
            # Check for errors
            if response.status_code != 200:
                error_msg = 'Unknown error'
                try:
                    error_data = response.json()
                    error_msg = error_data.get('message', error_data.get('error', 'Unknown error'))
                except:
                    error_msg = response.text or f'HTTP {response.status_code}'
                
                raise Exception(f'Generation failed: {error_msg}')
            
            # Save file if output_path provided
            if output_path:
                with open(output_path, 'wb') as f:
                    f.write(response.content)
                print(f'✅ Document saved to {output_path}')
            
            return response.content
            
    except requests.exceptions.RequestException as e:
        print(f'❌ Request error: {e}')
        raise
    except Exception as e:
        print(f'❌ Error: {e}')
        raise

# Example usage
if __name__ == '__main__':
    # Generate PDF
    generate_document(
        template_path='invoice_template.docx',
        data_path='clients.csv',
        output_format='pdf',
        output_path='invoices.pdf'
    )
    
    # Generate DOCX
    generate_document(
        template_path='certificate_template.docx',
        data_path='students.xlsx',
        output_format='docx',
        output_path='certificates.docx'
    )
📦 Install: pip install requests
💡 Environment Variable: Store API key securely: export DOC_CRAFTER_API_KEY="your-api-key-here" Then use: API_KEY = os.getenv('DOC_CRAFTER_API_KEY')

Using PHP

PHP
<?php

$apiUrl = 'https://doc-crafter.medevtech.net/generator';
$apiKey = 'your-api-key-here'; // Store in config file

function generateDocument($templatePath, $dataPath, $outputFormat = 'docx', $outputPath = null) {
    global $apiUrl, $apiKey;
    
    // Create CURLFile objects
    $templateFile = new CURLFile($templatePath, 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', basename($templatePath));
    $dataFile = new CURLFile($dataPath, 'text/csv', basename($dataPath));
    
    // Prepare POST data
    $postData = [
        'template' => $templateFile,
        'data' => $dataFile,
        'output_format' => $outputFormat
    ];
    
    // Initialize cURL
    $ch = curl_init();
    
    curl_setopt_array($ch, [
        CURLOPT_URL => $apiUrl,
        CURLOPT_POST => true,
        CURLOPT_POSTFIELDS => $postData,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_HTTPHEADER => [
            'X-API-Key: ' . $apiKey
        ],
        CURLOPT_TIMEOUT => 300, // 5 minutes
        CURLOPT_FOLLOWLOCATION => true
    ]);
    
    // Execute request
    $response = curl_exec($ch);
    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    $error = curl_error($ch);
    
    curl_close($ch);
    
    // Handle errors
    if ($error) {
        throw new Exception("cURL Error: " . $error);
    }
    
    if ($httpCode !== 200) {
        $errorData = json_decode($response, true);
        $errorMsg = $errorData['message'] ?? $errorData['error'] ?? "HTTP $httpCode";
        throw new Exception("Generation failed: $errorMsg");
    }
    
    // Save file if output path provided
    if ($outputPath) {
        file_put_contents($outputPath, $response);
        echo "✅ Document saved to $outputPath\n";
    }
    
    return $response;
}

// Example usage
try {
    // Generate PDF
    generateDocument(
        'invoice_template.docx',
        'clients.csv',
        'pdf',
        'invoices.pdf'
    );
    
    // Generate DOCX
    generateDocument(
        'certificate_template.docx',
        'students.xlsx',
        'docx',
        'certificates.docx'
    );
    
} catch (Exception $e) {
    echo "❌ Error: " . $e->getMessage() . "\n";
}

?>
📝 Note: Make sure allow_url_fopen is enabled in your PHP configuration, or use cURL extension (recommended).

📝 Step 4: Template and Data Format

Template Format (DOCX)

Your DOCX template should contain placeholders wrapped in curly braces that match your data column names.

DOCX Template Example
Invoice #INV-{invoice_number}

Client Information:
Name: {client_name}
Email: {client_email}
Phone: {client_phone}

Invoice Details:
Amount: {amount}
Date: {date}
Due Date: {due_date}

Thank you for your business!

Data File Format (CSV)

CSV Example
client_name,client_email,client_phone,invoice_number,amount,date,due_date
John Smith,john@example.com,+1234567890,INV-001,$1000,2025-01-01,2025-01-15
Jane Doe,jane@example.com,+0987654321,INV-002,$2500,2025-01-02,2025-01-16
Bob Johnson,bob@example.com,+1122334455,INV-003,$500,2025-01-03,2025-01-17

Data File Format (Excel)

Excel Requirements:
  • First row must contain headers
  • Headers are automatically converted to snake_case
  • Example: Client Nameclient_name
  • Only the first sheet is read by default
  • Supports formulas (reads calculated values)

Column Name Normalization

Column names are automatically normalized to match template placeholders:

⚠️ Important:
  • All rows must have the same columns
  • No empty/null values allowed
  • First row determines expected structure
  • Template placeholders must match normalized column names

⚠️ Step 5: Error Handling

Common Errors and Solutions

401 Unauthorized

Cause: Missing or invalid API key

Solution:

  • Check that X-API-Key header is included
  • Verify API key is correct (no extra spaces)
  • Ensure API key is active in Admin Dashboard
  • Check if API key has expired
403 Forbidden

Cause: Insufficient permissions or expired key

Solution:

  • Verify role has create_document_generation permission
  • Check API key expiration date
  • Ensure API key is not deactivated
  • Contact administrator to update permissions
400 Bad Request

Common Causes:

  • Missing template or data file
  • Invalid file format (not DOCX, CSV, or Excel)
  • Invalid output_format value (must be "docx" or "pdf")
  • Data validation failed (empty cells, missing columns)
413 Payload Too Large

Cause: File size exceeds limits

Limits:

  • Template files: Max 25MB
  • Data files: Max 50MB

Solution: Reduce file size or split data into multiple requests

500 Internal Server Error

Cause: Server-side error during processing

Solution:

  • Check template file is not corrupted
  • Verify data file format is correct
  • Try with smaller dataset first
  • Contact support if issue persists

Error Response Format

JSON Error Response
{
  "code": 401,
  "error": "Unauthorized",
  "message": "Missing X-API-Key header"
}

Best Practices for Error Handling

✨ Step 6: Best Practices

Security

Performance

Data Preparation

Template Design

🎯 Step 7: Complete Working Example

Here's a complete example showing the entire flow from getting an API key to generating a document:

Scenario: Generate Invoice PDFs

1 Get API Key

Login to Admin Dashboard → API Keys → Create New → Copy key

2 Prepare Template (invoice_template.docx)
INVOICE

Invoice Number: {invoice_number}
Date: {date}

Bill To:
{client_name}
{client_address}

Items:
{items}

Total: {total_amount}

Thank you!
3 Prepare Data (invoices.csv)
invoice_number,date,client_name,client_address,items,total_amount
INV-001,2025-01-15,John Smith,123 Main St,Product A - $100,100.00
INV-002,2025-01-16,Jane Doe,456 Oak Ave,Product B - $200,200.00
4 Generate Documents (Node.js Example)
const FormData = require('form-data');
const fs = require('fs');
const axios = require('axios');

async function generateInvoices() {
  const formData = new FormData();
  formData.append('template', fs.createReadStream('invoice_template.docx'));
  formData.append('data', fs.createReadStream('invoices.csv'));
  formData.append('output_format', 'pdf');

  try {
    const response = await axios.post(
      'https://doc-crafter.medevtech.net/generator',
      formData,
      {
        headers: {
          'X-API-Key': process.env.API_KEY,
          ...formData.getHeaders()
        },
        responseType: 'stream'
      }
    );

    // Save the file
    const writer = fs.createWriteStream('invoices.pdf');
    response.data.pipe(writer);

    writer.on('finish', () => {
      console.log('✅ Invoices generated successfully!');
    });
  } catch (error) {
    console.error('❌ Error:', error.response?.data || error.message);
  }
}

generateInvoices();
5 Result

You'll receive a PDF file with 2 pages, one invoice per client, ready to download or send.

🆘 Support & Resources

Need Help?

Rate Limits

Default rate limit: 1000 requests per minute per API key. Contact support for higher limits.

File Size Limits

Supported Formats