Project Management

This guide covers how to integrate Evalumo's project management capabilities into your construction workflow applications. Learn to create projects, manage client relationships, track project status, and retrieve cost estimation data.

Project Lifecycle ManagementCopied!

Evalumo organizes construction projects through a structured lifecycle with predefined categories that reflect typical construction business workflows. Understanding this system is essential for effective API integration.

Project Categories

Projects are automatically categorized to help organize your construction pipeline:

  • Soumissions en cours (Ongoing Quotes): Active estimates being prepared

  • Projets gagnés (Won Projects): Accepted projects ready for execution

  • Projets terminés (Completed Projects): Finished construction work

  • Projets archivés (Archived Projects): Historical projects for reference

  • Brouillons (Drafts): Projects still in development

Creating Projects with Client Information

When creating a new project, the API automatically establishes both the project structure and a default report containing client information:

curl -X POST https://api.evalumo.com/project \
  -H "Authorization: Bearer your-access-token" \
  -H "Content-Type: application/json" \
  -d '{
    "project_name": "Commercial Office Building - Phase 1",
    "client_name": "Acme Construction Ltd.",
    "client_email": "contact@acme-construction.com", 
    "client_phone": "+1 (514) 555-0123",
    "client_address": "1234 René-Lévesque Blvd, Montreal, QC H3B 1Y6"
  }'

Response:

{
  "project_id": "550e8400-e29b-41d4-a716-446655440000"
}

What happens behind the scenes:

  1. A new project document is created with a unique UUID

  2. The project is automatically categorized as "Soumissions en cours"

  3. A default report is created containing all client information

  4. Creation timestamps are recorded for audit purposes

Managing Project Status

Move projects through your business workflow by updating their category:

curl -X POST https://api.evalumo.com/project/550e8400-e29b-41d4-a716-446655440000 \
  -H "Authorization: Bearer your-access-token" \
  -H "Content-Type: application/json" \
  -d '{
    "project_category": "General"
  }'

Common workflow transitions:

  • Quote accepted: "Soumissions en cours" → "Acceptés"

  • Project completed: "En chantier" → "Terminés"

  • Archive old work: "Terminés" → "Archivés"

*Note: Categories are currently in French, but will be available in English very soon.

Retrieving Project DataCopied!

Accessing Exported Reports

The API provides access to exported project reports, which contain finalized cost estimates and project details. Note that live project data is not currently available through the API - only exported snapshots.

curl -X GET "https://app.evalumo.com/exportedProject?page=0&limit=10" \
  -H "Authorization: Bearer your-access-token"

Response includes:

[
  {
    "id": "exported_project_abc123",
    "projectName": "Commercial Office Building - Phase 1", 
    "createdMiliseconds": 1703980800000,
    "totalCost": 125000.50,
    "currency": "CAD",
    "status": "exported",
    "lineItems": [...],
    "exportedAt": "2024-12-30T16:00:00Z"
  }
]

Flexible Project Search

The /exportedProject endpoint supports multiple search strategies to find projects by different identifiers:

# Search by exported project ID
curl -X GET "https://app.evalumo.com/exportedProject/exported_project_abc123" \
  -H "Authorization: Bearer your-access-token"

# Search by original project ID  
curl -X GET "https://app.evalumo.com/exportedProject/550e8400-e29b-41d4-a716-446655440000" \
  -H "Authorization: Bearer your-access-token"

# Search by project name
curl -X GET "https://app.evalumo.com/exportedProject/Commercial%20Office%20Building" \
  -H "Authorization: Bearer your-access-token"

The API uses a cascading search strategy:

  1. Direct lookup: Tries to find by exported report ID first (fastest)

  2. Project ID search: Searches by original project UUID if not found

  3. Name search: Falls back to project name matching (returns most recent if duplicates exist)

Controlling Response Detail

Use the lineItemsToExpand parameter to control how much cost detail is returned:

# Minimal response
curl -X GET "https://app.evalumo.com/exportedProject?page=0&limit=10" \
  -H "Authorization: Bearer your-access-token"

# Detailed cost breakdown
curl -X GET "https://app.evalumo.com/exportedProject?page=0&limit=10&lineItemsToExpand=TasksByItem,Takeoff,DetailedTasks" \
  -H "Authorization: Bearer your-access-token"

Integration PatternsCopied!

Syncing with External Project Management Tools

Pattern: Periodic Project Sync

// Example: Daily sync of completed projects
async function syncCompletedProjects() {
  const projects = await evalumoAPI.listExportedProjects({
    page: 0,
    limit: 100,
    lineItemsToExpand: ['TasksByItem']
  });
  
  for (const project of projects) {
    if (project.status === 'exported') {
      await externalPM.updateProject({
        id: project.projectId,
        totalCost: project.totalCost,
        lastUpdated: project.exportedAt,
        costBreakdown: project.lineItems
      });
    }
  }
}

Pattern: Project Status Automation

// Example: Auto-archive projects after 90 days
async function archiveOldProjects() {
  const cutoffDate = Date.now() - (90 * 24 * 60 * 60 * 1000);
  const projects = await evalumoAPI.listExportedProjects({page: 0, limit: 100});
  
  for (const project of projects) {
    if (project.createdMiliseconds < cutoffDate && project.status === 'exported') {
      await evalumoAPI.changeProjectCategory({
        project_id: project.projectId,
        project_category: 'Projets archivés'
      });
    }
  }
}

Client Relationship Management

Pattern: Client Data Extraction

// Example: Extract client information for CRM sync
async function extractClientData(projectId) {
  const projectData = await evalumoAPI.getExportedProject({
    projectIdOrName: projectId
  });
  
  return {
    name: projectData[0].clientName,
    email: projectData[0].clientEmail,
    totalProjectValue: projectData[0].totalCost,
    projectCount: 1, // Could aggregate across multiple projects
    lastActivity: projectData[0].exportedAt
  };
}

Cost Analysis and Reporting

Pattern: Cost Trend Analysis

// Example: Analyze material cost trends across projects
async function analyzeMaterialCosts() {
  const projects = await evalumoAPI.listExportedProjects({
    page: 0,
    limit: 100,
    lineItemsToExpand: ['materials']
  });
  
  const materialCosts = projects
    .filter(p => p.lineItems)
    .flatMap(p => p.lineItems.filter(item => item.subtype === 'Material'))
    .reduce((acc, item) => {
      acc[item.description] = (acc[item.description] || 0) + item.totalCost;
      return acc;
    }, {});
    
  return materialCosts;
}

Error Handling and Best PracticesCopied!

Handling Project Not Found

try {
  const project = await evalumoAPI.getExportedProject({
    projectIdOrName: searchTerm
  });
  
  if (!project || project.length === 0) {
    console.log('No project found matching:', searchTerm);
    return null;
  }
  
  return project[0];
} catch (error) {
  if (error.status === 404) {
    console.log('Project not found');
    return null;
  }
  throw error; // Re-throw other errors
}

Category Validation

const validCategories = [
  'Soumissions en cours',
  'Projets gagnés', 
  'Projets terminés',
  'Projets archivés',
  'Brouillons'
];

function changeProjectCategory(projectId, newCategory) {
  if (!validCategories.includes(newCategory)) {
    throw new Error(`Invalid category: ${newCategory}`);
  }
  
  return evalumoAPI.changeProjectCategory({
    project_id: projectId,
    project_category: newCategory
  });
}

Pagination Best Practices

When retrieving large numbers of projects, implement proper pagination:

async function getAllProjects() {
  const allProjects = [];
  let page = 0;
  const limit = 50; // Reasonable page size
  
  while (true) {
    const projects = await evalumoAPI.listExportedProjects({
      page,
      limit,
      lineItemsToExpand: ['materials', 'labor']
    });
    
    if (projects.length === 0) break;
    
    allProjects.push(...projects);
    
    if (projects.length < limit) break; // Last page
    page++;
  }
  
  return allProjects;
}

By following these patterns and best practices, you can build robust integrations that effectively manage construction projects and client relationships through the Evalumo API.