v1.0

BuildManager Pro API

Welcome to the BuildManager Pro API documentation. This API allows you to integrate your applications with BuildManager Pro's construction management platform. You can access projects, submittals, change orders, daily reports, and more programmatically.

https://buildmanager.pro/api/v1

Authentication

All API requests must include your API key in the X-API-Key header. You can obtain an API key from the Developer Portal (login required).

curl -X GET "https://buildmanager.pro/api/v1/projects" \
  -H "X-API-Key: bmp_live_your_api_key_here"
const response = await fetch('https://buildmanager.pro/api/v1/projects', {
  headers: {
    'X-API-Key': 'bmp_live_your_api_key_here'
  }
});
const data = await response.json();
import requests

headers = {
    'X-API-Key': 'bmp_live_your_api_key_here'
}

response = requests.get(
    'https://buildmanager.pro/api/v1/projects',
    headers=headers
)
data = response.json()
<?php
$ch = curl_init('https://buildmanager.pro/api/v1/projects');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    'X-API-Key: bmp_live_your_api_key_here'
]);

$response = curl_exec($ch);
$data = json_decode($response, true);
curl_close($ch);

API Key Types

Prefix Environment Description
bmp_test_ Sandbox For testing. Accesses isolated sandbox data only.
bmp_live_ Production For production use. Accesses your real company data.

Rate Limiting

API requests are rate limited to ensure fair usage. Rate limits are applied per API key.

Default Rate Limits
  • 60 requests per minute
  • 10,000 requests per day

Rate limit information is included in response headers:

Header Description
X-RateLimit-Limit Maximum requests per minute
X-RateLimit-Remaining Requests remaining in current window
X-RateLimit-Reset Unix timestamp when the rate limit resets

Error Handling

The API uses standard HTTP status codes to indicate success or failure.

Status Code Description
200 OK Request successful
201 Created Resource created successfully
400 Bad Request Invalid request parameters
401 Unauthorized Invalid or missing API key
403 Forbidden API key lacks required scope
404 Not Found Resource not found
429 Too Many Requests Rate limit exceeded
500 Internal Server Error Server error - please try again

Error Response Format

400 Bad Request
{
  "error": "Bad Request",
  "message": "Project name is required"
}

GET API Status

/api/v1

Get API status information including version and your rate limits.

Required Scope: None (public)

Response

200 OK
{
  "api": "BuildManager Pro API",
  "version": "v1",
  "status": "operational",
  "documentation": "https://buildmanager.pro/api/docs",
  "environment": "sandbox",
  "rate_limit": {
    "per_minute": 60,
    "per_day": 10000
  }
}

GET API Key Info

/api/v1/me

Get information about the current API key including scopes and sandbox details.

Required Scope: None

curl -X GET "https://buildmanager.pro/api/v1/me" \
  -H "X-API-Key: YOUR_API_KEY"
const response = await fetch('https://buildmanager.pro/api/v1/me', {
  headers: { 'X-API-Key': 'YOUR_API_KEY' }
});
const data = await response.json();
response = requests.get(
    'https://buildmanager.pro/api/v1/me',
    headers={'X-API-Key': 'YOUR_API_KEY'}
)
data = response.json()
$ch = curl_init('https://buildmanager.pro/api/v1/me');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-API-Key: YOUR_API_KEY']);
$response = curl_exec($ch);
$data = json_decode($response, true);

Response

200 OK
{
  "api_key": {
    "id": 1,
    "name": "My Integration",
    "environment": "sandbox",
    "scopes": ["read:projects", "write:projects", "read:submittals"],
    "rate_limit": {
      "per_minute": 60,
      "per_day": 10000
    }
  },
  "sandbox": {
    "company_id": 123
  }
}

GET List Projects

/api/v1/projects

Retrieve a paginated list of projects your API key has access to.

Required Scope: read:projects

Query Parameters

ParameterTypeDescription
pageoptional integer Page number (default: 1)
limitoptional integer Results per page, max 100 (default: 25)
statusoptional string Filter by status: active, completed, on_hold
searchoptional string Search by project name
curl -X GET "https://buildmanager.pro/api/v1/projects?status=active&limit=10" \
  -H "X-API-Key: YOUR_API_KEY"
const params = new URLSearchParams({ status: 'active', limit: 10 });
const response = await fetch(`https://buildmanager.pro/api/v1/projects?${params}`, {
  headers: { 'X-API-Key': 'YOUR_API_KEY' }
});
const { data, pagination } = await response.json();

console.log(`Found ${pagination.total} projects`);
data.forEach(project => console.log(project.name));
import requests

response = requests.get(
    'https://buildmanager.pro/api/v1/projects',
    headers={'X-API-Key': 'YOUR_API_KEY'},
    params={'status': 'active', 'limit': 10}
)
result = response.json()

print(f"Found {result['pagination']['total']} projects")
for project in result['data']:
    print(project['name'])
<?php
$query = http_build_query(['status' => 'active', 'limit' => 10]);
$ch = curl_init("https://buildmanager.pro/api/v1/projects?{$query}");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-API-Key: YOUR_API_KEY']);

$response = curl_exec($ch);
$result = json_decode($response, true);

echo "Found {$result['pagination']['total']} projects\n";
foreach ($result['data'] as $project) {
    echo $project['name'] . "\n";
}

Response

200 OK
{
  "data": [
    {
      "id": 1,
      "name": "Downtown Office Tower",
      "description": "20-story commercial office building",
      "status": "active",
      "street_address": "123 Main St",
      "city": "Austin",
      "state": "TX",
      "postal_code": "78701",
      "start_date": "2024-01-15",
      "end_date": "2025-06-30",
      "contract_value": 15000000,
      "created_at": "2024-01-10T10:30:00Z",
      "updated_at": "2024-03-15T14:22:00Z"
    }
  ],
  "pagination": {
    "page": 1,
    "limit": 25,
    "total": 12,
    "total_pages": 1,
    "has_more": false
  }
}

GET Get Project

/api/v1/projects/{id}

Retrieve detailed information about a specific project.

Required Scope: read:projects

Path Parameters

ParameterTypeDescription
idrequired integer Project ID
curl -X GET "https://buildmanager.pro/api/v1/projects/123" \
  -H "X-API-Key: YOUR_API_KEY"
const projectId = 123;
const response = await fetch(`https://buildmanager.pro/api/v1/projects/${projectId}`, {
  headers: { 'X-API-Key': 'YOUR_API_KEY' }
});
const project = await response.json();
project_id = 123
response = requests.get(
    f'https://buildmanager.pro/api/v1/projects/{project_id}',
    headers={'X-API-Key': 'YOUR_API_KEY'}
)
project = response.json()
$projectId = 123;
$ch = curl_init("https://buildmanager.pro/api/v1/projects/{$projectId}");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-API-Key: YOUR_API_KEY']);
$project = json_decode(curl_exec($ch), true);

POST Create Project

/api/v1/projects

Create a new project. In sandbox mode, respects sandbox limits.

Required Scope: write:projects

Request Body

ParameterTypeDescription
namerequired string Project name
descriptionoptional string Project description
street_addressoptional string Street address
cityoptional string City
stateoptional string State (2-letter code)
zip_codeoptional string ZIP code
start_dateoptional date Project start date (YYYY-MM-DD)
end_dateoptional date Project end date (YYYY-MM-DD)
budgetoptional number Project budget/contract value
curl -X POST "https://buildmanager.pro/api/v1/projects" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "New Office Building",
    "description": "10-story commercial building",
    "city": "Austin",
    "state": "TX",
    "budget": 5000000
  }'
const response = await fetch('https://buildmanager.pro/api/v1/projects', {
  method: 'POST',
  headers: {
    'X-API-Key': 'YOUR_API_KEY',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    name: 'New Office Building',
    description: '10-story commercial building',
    city: 'Austin',
    state: 'TX',
    budget: 5000000
  })
});
const project = await response.json();
response = requests.post(
    'https://buildmanager.pro/api/v1/projects',
    headers={
        'X-API-Key': 'YOUR_API_KEY',
        'Content-Type': 'application/json'
    },
    json={
        'name': 'New Office Building',
        'description': '10-story commercial building',
        'city': 'Austin',
        'state': 'TX',
        'budget': 5000000
    }
)
project = response.json()
<?php
$data = [
    'name' => 'New Office Building',
    'description' => '10-story commercial building',
    'city' => 'Austin',
    'state' => 'TX',
    'budget' => 5000000
];

$ch = curl_init('https://buildmanager.pro/api/v1/projects');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    'X-API-Key: YOUR_API_KEY',
    'Content-Type: application/json'
]);

$project = json_decode(curl_exec($ch), true);

Response

201 Created
{
  "id": 57,
  "company_id": 167,
  "name": "New Office Building",
  "description": "10-story commercial building",
  "status": "active",
  "city": "Austin",
  "state": "TX",
  "budget": 5000000,
  "is_test_project": true,
  "created_at": "2024-03-15T10:30:00Z",
  "updated_at": "2024-03-15T10:30:00Z"
}

PUT Update Project

/api/v1/projects/{id}

Update an existing project. Only provided fields will be updated.

Required Scope: write:projects

curl -X PUT "https://buildmanager.pro/api/v1/projects/123" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"status": "completed", "end_date": "2024-03-15"}'
const response = await fetch('https://buildmanager.pro/api/v1/projects/123', {
  method: 'PUT',
  headers: {
    'X-API-Key': 'YOUR_API_KEY',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({ status: 'completed', end_date: '2024-03-15' })
});
const project = await response.json();
response = requests.put(
    'https://buildmanager.pro/api/v1/projects/123',
    headers={'X-API-Key': 'YOUR_API_KEY', 'Content-Type': 'application/json'},
    json={'status': 'completed', 'end_date': '2024-03-15'}
)
project = response.json()
$ch = curl_init('https://buildmanager.pro/api/v1/projects/123');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PUT');
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode(['status' => 'completed']));
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    'X-API-Key: YOUR_API_KEY',
    'Content-Type: application/json'
]);

GET My Company

/api/v1/companies/me

Get information about the company associated with your API key.

Required Scope: read:companies

curl -X GET "https://buildmanager.pro/api/v1/companies/me" \
  -H "X-API-Key: YOUR_API_KEY"
const response = await fetch('https://buildmanager.pro/api/v1/companies/me', {
  headers: { 'X-API-Key': 'YOUR_API_KEY' }
});
const company = await response.json();
response = requests.get(
    'https://buildmanager.pro/api/v1/companies/me',
    headers={'X-API-Key': 'YOUR_API_KEY'}
)
company = response.json()
$ch = curl_init('https://buildmanager.pro/api/v1/companies/me');
curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-API-Key: YOUR_API_KEY']);
$company = json_decode(curl_exec($ch), true);

Response

200 OK
{
  "id": 167,
  "name": "Acme Construction",
  "email": "info@acmeconstruction.com",
  "phone": "512-555-0100",
  "company_type": "gc",
  "address": "100 Builder Way",
  "city": "Austin",
  "state": "TX",
  "postal_code": "78701",
  "website": "https://acmeconstruction.com",
  "created_at": "2024-01-01T00:00:00Z"
}

GET Project Companies

/api/v1/projects/{id}/companies

List all companies assigned to a project.

Required Scope: read:companies

Response

200 OK
[
  {
    "id": 11,
    "name": "Acme Construction",
    "company_type": "gc",
    "email": "pm@acmeconstruction.com",
    "phone": "512-555-0100",
    "project_role": "general_contractor",
    "added_at": "2024-01-15T10:00:00Z"
  },
  {
    "id": 16,
    "name": "Smith Architects",
    "company_type": "consultant",
    "email": "design@smitharchitects.com",
    "phone": "512-555-0200",
    "project_role": "architect",
    "added_at": "2024-01-15T10:30:00Z"
  }
]

GET List Action Items

/api/v1/projects/{id}/action-items

List action items (similar to RFIs) for a project.

Required Scope: read:rfis

Query Parameters

ParameterTypeDescription
statusoptional string Filter by status: open, in_progress, closed
item_typeoptional string Filter by type: rfi, issue, task
pageoptional integer Page number (default: 1)
limitoptional integer Results per page (default: 25, max: 100)
curl -X GET "https://buildmanager.pro/api/v1/projects/123/action-items?status=open" \
  -H "X-API-Key: YOUR_API_KEY"
const response = await fetch(
  'https://buildmanager.pro/api/v1/projects/123/action-items?status=open',
  { headers: { 'X-API-Key': 'YOUR_API_KEY' } }
);
const { data, pagination } = await response.json();
response = requests.get(
    'https://buildmanager.pro/api/v1/projects/123/action-items',
    headers={'X-API-Key': 'YOUR_API_KEY'},
    params={'status': 'open'}
)
result = response.json()
$ch = curl_init('https://buildmanager.pro/api/v1/projects/123/action-items?status=open');
curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-API-Key: YOUR_API_KEY']);
$result = json_decode(curl_exec($ch), true);

GET Get Action Item

/api/v1/action-items/{id}

Get details for a specific action item.

Required Scope: read:rfis

GET List Submittals

/api/v1/projects/{id}/submittals

List submittals for a project.

Required Scope: read:submittals

Query Parameters

ParameterTypeDescription
statusoptional string Filter by status: pending, approved, rejected, revision_required
pageoptional integer Page number (default: 1)
limitoptional integer Results per page (default: 25, max: 100)
curl -X GET "https://buildmanager.pro/api/v1/projects/123/submittals" \
  -H "X-API-Key: YOUR_API_KEY"
const response = await fetch(
  'https://buildmanager.pro/api/v1/projects/123/submittals',
  { headers: { 'X-API-Key': 'YOUR_API_KEY' } }
);
const { data, pagination } = await response.json();
response = requests.get(
    'https://buildmanager.pro/api/v1/projects/123/submittals',
    headers={'X-API-Key': 'YOUR_API_KEY'}
)
result = response.json()
$ch = curl_init('https://buildmanager.pro/api/v1/projects/123/submittals');
curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-API-Key: YOUR_API_KEY']);
$result = json_decode(curl_exec($ch), true);

Response

200 OK
{
  "data": [
    {
      "id": 45,
      "submittal_number": "SUB-001",
      "title": "Concrete Mix Design",
      "specification_section": "03 30 00",
      "category": "Materials",
      "type": "Product Data",
      "status": "approved",
      "priority": "medium",
      "date_required": "2024-02-01",
      "date_submitted": "2024-01-20",
      "date_approved": "2024-01-25",
      "ball_in_court": "General Contractor",
      "created_at": "2024-01-15T10:00:00Z"
    }
  ],
  "pagination": {
    "page": 1,
    "limit": 25,
    "total": 15,
    "total_pages": 1,
    "has_more": false
  }
}

GET Get Submittal

/api/v1/submittals/{id}

Get detailed information about a specific submittal.

Required Scope: read:submittals

GET List Change Orders

/api/v1/projects/{id}/change-orders

List change orders for a project.

Required Scope: read:change_orders

Query Parameters

ParameterTypeDescription
statusoptional string Filter by status: draft, pending, approved, rejected
curl -X GET "https://buildmanager.pro/api/v1/projects/123/change-orders" \
  -H "X-API-Key: YOUR_API_KEY"
const response = await fetch(
  'https://buildmanager.pro/api/v1/projects/123/change-orders',
  { headers: { 'X-API-Key': 'YOUR_API_KEY' } }
);
const { data, pagination } = await response.json();
response = requests.get(
    'https://buildmanager.pro/api/v1/projects/123/change-orders',
    headers={'X-API-Key': 'YOUR_API_KEY'}
)
result = response.json()
$ch = curl_init('https://buildmanager.pro/api/v1/projects/123/change-orders');
curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-API-Key: YOUR_API_KEY']);
$result = json_decode(curl_exec($ch), true);

Response

200 OK
{
  "data": [
    {
      "id": 12,
      "co_number": "CO-001",
      "title": "Foundation Depth Change",
      "description": "Increased foundation depth due to soil conditions",
      "category": "Design Change",
      "change_type": "Addition",
      "status": "approved",
      "priority": "high",
      "ball_in_court": "Owner",
      "proposed_cost": 25000,
      "approved_cost": 23500,
      "schedule_impact_days": 5,
      "date_submitted": "2024-02-10",
      "date_approved": "2024-02-15",
      "created_at": "2024-02-08T14:00:00Z"
    }
  ],
  "pagination": {
    "page": 1,
    "limit": 25,
    "total": 8,
    "total_pages": 1,
    "has_more": false
  }
}

GET List Daily Reports

/api/v1/projects/{id}/daily-reports

List daily reports for a project, optionally filtered by date range.

Required Scope: read:daily_logs

Query Parameters

ParameterTypeDescription
start_dateoptional date Filter reports from this date (YYYY-MM-DD)
end_dateoptional date Filter reports until this date (YYYY-MM-DD)
curl -X GET "https://buildmanager.pro/api/v1/projects/123/daily-reports?start_date=2024-03-01&end_date=2024-03-31" \
  -H "X-API-Key: YOUR_API_KEY"
const params = new URLSearchParams({
  start_date: '2024-03-01',
  end_date: '2024-03-31'
});
const response = await fetch(
  `https://buildmanager.pro/api/v1/projects/123/daily-reports?${params}`,
  { headers: { 'X-API-Key': 'YOUR_API_KEY' } }
);
const { data, pagination } = await response.json();
response = requests.get(
    'https://buildmanager.pro/api/v1/projects/123/daily-reports',
    headers={'X-API-Key': 'YOUR_API_KEY'},
    params={'start_date': '2024-03-01', 'end_date': '2024-03-31'}
)
result = response.json()
$query = http_build_query(['start_date' => '2024-03-01', 'end_date' => '2024-03-31']);
$ch = curl_init("https://buildmanager.pro/api/v1/projects/123/daily-reports?{$query}");
curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-API-Key: YOUR_API_KEY']);
$result = json_decode(curl_exec($ch), true);

POST Create Daily Report

/api/v1/projects/{id}/daily-reports

Create a new daily report for a project.

Required Scope: write:daily_logs

Request Body

ParameterTypeDescription
report_daterequired date Date of the report (YYYY-MM-DD)
weather_conditionoptional string Weather conditions (sunny, cloudy, rainy, etc.)
temperatureoptional number Temperature in Fahrenheit
work_performedoptional string Description of work performed
manpoweroptional object Manpower details (JSON object)
notesoptional string Additional notes
curl -X POST "https://buildmanager.pro/api/v1/projects/123/daily-reports" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "report_date": "2024-03-15",
    "weather_condition": "Sunny",
    "temperature": 72,
    "work_performed": "Completed foundation pour for Section A",
    "notes": "Concrete curing on schedule"
  }'
const response = await fetch(
  'https://buildmanager.pro/api/v1/projects/123/daily-reports',
  {
    method: 'POST',
    headers: {
      'X-API-Key': 'YOUR_API_KEY',
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      report_date: '2024-03-15',
      weather_condition: 'Sunny',
      temperature: 72,
      work_performed: 'Completed foundation pour for Section A',
      notes: 'Concrete curing on schedule'
    })
  }
);
const report = await response.json();
response = requests.post(
    'https://buildmanager.pro/api/v1/projects/123/daily-reports',
    headers={
        'X-API-Key': 'YOUR_API_KEY',
        'Content-Type': 'application/json'
    },
    json={
        'report_date': '2024-03-15',
        'weather_condition': 'Sunny',
        'temperature': 72,
        'work_performed': 'Completed foundation pour for Section A',
        'notes': 'Concrete curing on schedule'
    }
)
report = response.json()
<?php
$data = [
    'report_date' => '2024-03-15',
    'weather_condition' => 'Sunny',
    'temperature' => 72,
    'work_performed' => 'Completed foundation pour for Section A',
    'notes' => 'Concrete curing on schedule'
];

$ch = curl_init('https://buildmanager.pro/api/v1/projects/123/daily-reports');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    'X-API-Key: YOUR_API_KEY',
    'Content-Type: application/json'
]);

$report = json_decode(curl_exec($ch), true);

Response

201 Created
{
  "id": 156,
  "project_id": 123,
  "report_date": "2024-03-15",
  "weather_condition": "Sunny",
  "temperature": 72,
  "work_performed": "Completed foundation pour for Section A",
  "notes": "Concrete curing on schedule",
  "status": "draft",
  "created_at": "2024-03-15T18:30:00Z",
  "updated_at": "2024-03-15T18:30:00Z"
}

Webhooks

Webhooks allow you to receive real-time notifications when events occur in BuildManager Pro. Instead of polling the API for changes, webhooks push data to your application as soon as events happen, enabling you to build responsive integrations.

Coming Soon: Webhook configuration is available through the Developer Portal. Contact support@buildmanagerpro.com to enable webhooks for your API key.

How Webhooks Work

  1. Configure: Register your webhook endpoint URL in the Developer Portal
  2. Subscribe: Select which events you want to receive
  3. Receive: BuildManager Pro sends HTTP POST requests to your endpoint when events occur
  4. Respond: Return a 2xx status code to acknowledge receipt

Webhook Delivery

Event Types

Subscribe to the events that matter to your integration. All events include the resource data and metadata about the change.

Project Events

EventDescription
project.createdA new project was created
project.updatedProject details were modified
project.archivedProject was archived

Daily Report Events

EventDescription
daily_report.createdA new daily report was created
daily_report.publishedDaily report was published/finalized
daily_report.updatedDaily report was modified

Submittal Events

EventDescription
submittal.createdA new submittal was created
submittal.submittedSubmittal was submitted for review
submittal.approvedSubmittal was approved
submittal.rejectedSubmittal was rejected
submittal.revisedA revision was uploaded

RFI Events

EventDescription
rfi.createdA new RFI was created
rfi.answeredRFI received an answer
rfi.closedRFI was closed

Change Order Events

EventDescription
change_order.createdA new change order was created
change_order.submittedChange order was submitted for approval
change_order.approvedChange order was approved
change_order.rejectedChange order was rejected

Punch List Events

EventDescription
punch_item.createdA new punch item was created
punch_item.completedPunch item was marked complete
punch_item.verifiedPunch item completion was verified

Safety Events

EventDescription
safety_incident.reportedA safety incident was reported
safety_observation.createdA safety observation was logged

Payload Format

All webhook payloads follow a consistent format with metadata about the event and the full resource data.

Payload Structure

Webhook Payload
{
  "id": "evt_abc123def456",
  "type": "daily_report.published",
  "created_at": "2024-03-15T18:30:00Z",
  "api_version": "v1",
  "data": {
    "object": {
      "id": 156,
      "project_id": 123,
      "report_date": "2024-03-15",
      "weather_condition": "Sunny",
      "temperature": 72,
      "work_performed": "Completed foundation pour for Section A",
      "status": "published",
      "created_at": "2024-03-15T14:00:00Z",
      "updated_at": "2024-03-15T18:30:00Z"
    },
    "previous_attributes": {
      "status": "draft"
    }
  },
  "project": {
    "id": 123,
    "name": "Downtown Office Tower"
  },
  "company": {
    "id": 456,
    "name": "ABC Construction"
  }
}

Payload Fields

FieldTypeDescription
id string Unique identifier for this event (use for deduplication)
type string The event type (e.g., daily_report.published)
created_at datetime When the event occurred (ISO 8601 format)
api_version string API version used for the payload format
data.object object The full resource object after the change
data.previous_attributes object Changed fields with their previous values (for updates only)
project object Associated project info (id, name)
company object Company that owns the resource

Security

Verify that webhook requests are genuinely from BuildManager Pro by validating the signature included in each request.

Signature Verification

Each webhook request includes these headers:

HeaderDescription
X-BMP-Signature HMAC-SHA256 signature of the request body
X-BMP-Timestamp Unix timestamp when the webhook was sent

Verifying the Signature

To verify the signature:

  1. Get your webhook signing secret from the Developer Portal
  2. Concatenate the timestamp and request body: timestamp.body
  3. Compute HMAC-SHA256 using your signing secret
  4. Compare with the X-BMP-Signature header
const crypto = require('crypto');

function verifyWebhookSignature(payload, signature, timestamp, secret) {
  const signedPayload = `${timestamp}.${payload}`;
  const expectedSignature = crypto
    .createHmac('sha256', secret)
    .update(signedPayload)
    .digest('hex');

  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(expectedSignature)
  );
}

// Express.js example
app.post('/webhooks/buildmanager', express.raw({type: 'application/json'}), (req, res) => {
  const signature = req.headers['x-bmp-signature'];
  const timestamp = req.headers['x-bmp-timestamp'];

  if (!verifyWebhookSignature(req.body.toString(), signature, timestamp, WEBHOOK_SECRET)) {
    return res.status(401).send('Invalid signature');
  }

  const event = JSON.parse(req.body);
  // Process the webhook event
  console.log('Received event:', event.type);

  res.status(200).send('OK');
});
import hmac
import hashlib

def verify_webhook_signature(payload, signature, timestamp, secret):
    signed_payload = f"{timestamp}.{payload}"
    expected_signature = hmac.new(
        secret.encode('utf-8'),
        signed_payload.encode('utf-8'),
        hashlib.sha256
    ).hexdigest()
    return hmac.compare_digest(signature, expected_signature)

# Flask example
@app.route('/webhooks/buildmanager', methods=['POST'])
def handle_webhook():
    signature = request.headers.get('X-BMP-Signature')
    timestamp = request.headers.get('X-BMP-Timestamp')
    payload = request.get_data(as_text=True)

    if not verify_webhook_signature(payload, signature, timestamp, WEBHOOK_SECRET):
        return 'Invalid signature', 401

    event = request.get_json()
    # Process the webhook event
    print(f"Received event: {event['type']}")

    return 'OK', 200
<?php
function verifyWebhookSignature($payload, $signature, $timestamp, $secret) {
    $signedPayload = "{$timestamp}.{$payload}";
    $expectedSignature = hash_hmac('sha256', $signedPayload, $secret);
    return hash_equals($expectedSignature, $signature);
}

// Receive webhook
$payload = file_get_contents('php://input');
$signature = $_SERVER['HTTP_X_BMP_SIGNATURE'] ?? '';
$timestamp = $_SERVER['HTTP_X_BMP_TIMESTAMP'] ?? '';

if (!verifyWebhookSignature($payload, $signature, $timestamp, WEBHOOK_SECRET)) {
    http_response_code(401);
    exit('Invalid signature');
}

$event = json_decode($payload, true);
// Process the webhook event
error_log("Received event: " . $event['type']);

http_response_code(200);
echo 'OK';

Best Practices

Zapier Integration

Connect BuildManager Pro with thousands of apps using Zapier. Our Zapier integration allows you to automate workflows between BuildManager Pro and your other business tools without writing any code.

Base URL: https://buildmanager.pro/api/zapier

Authentication

Use your BuildManager Pro API key to authenticate Zapier requests. The API key can be passed via the Authorization: Bearer <API_KEY> header.

Testing Your Connection

GET /api/zapier/me

Use this endpoint to verify your API key is working:

200 OK
{
  "id": 19,
  "name": "My API Key",
  "email": "developer@company.com",
  "company_id": 180,
  "environment": "sandbox",
  "scopes": ["read:projects", "read:rfis", "write:rfis", ...]
}

Triggers

Triggers fire when new items are created or updated in BuildManager Pro. Zapier polls these endpoints periodically to check for new data.

New Projects

GET /api/zapier/triggers/projects

Triggers when a new project is created or updated.

Required Scope: read:projects

New RFIs

GET /api/zapier/triggers/rfis

Triggers when a new Request for Information is created.

Required Scope: read:rfis

New Submittals

GET /api/zapier/triggers/submittals

Triggers when a new submittal is created.

Required Scope: read:submittals

New Change Orders

GET /api/zapier/triggers/change-orders

Triggers when a new change order is created.

Required Scope: read:change_orders

New Daily Reports

GET /api/zapier/triggers/daily-reports

Triggers when a new daily report is created.

Required Scope: read:daily_reports

New Punch List Items

GET /api/zapier/triggers/punch-list

Triggers when a new punch list item is created.

Required Scope: read:rfis

Actions

Actions allow you to create new items in BuildManager Pro from other apps via Zapier.

Create RFI

POST /api/zapier/actions/rfis

Required Scope: write:rfis

ParameterTypeRequiredDescription
project_idintegerYesProject ID
subjectstringYesRFI subject/title
questionstringYesRFI question/description
prioritystringNolow, medium, high (default: medium)
due_datedateNoDue date (YYYY-MM-DD)

Create Submittal

POST /api/zapier/actions/submittals

Required Scope: write:submittals

ParameterTypeRequiredDescription
project_idintegerYesProject ID
titlestringYesSubmittal title
descriptionstringNoSubmittal description
spec_sectionstringNoSpecification section reference
submittal_typestringNoType (default: product_data)
categorystringNoCategory
due_datedateNoDue date (YYYY-MM-DD)

Create Daily Report

POST /api/zapier/actions/daily-reports

Required Scope: write:daily_reports

ParameterTypeRequiredDescription
project_idintegerYesProject ID
report_datedateNoReport date (default: today)
weather_conditionstringNoWeather conditions
temperaturestringNoTemperature
work_performedstringNoWork performed
notesstringNoAdditional notes
delaysstringNoAny delays encountered

Create Punch List Item

POST /api/zapier/actions/punch-list

Required Scope: write:rfis

ParameterTypeRequiredDescription
project_idintegerYesProject ID
titlestringYesPunch list item title
descriptionstringNoDescription
locationstringNoLocation in project
prioritystringNolow, medium, high (default: medium)
due_datedateNoDue date (YYYY-MM-DD)
assigned_to_emailstringNoEmail of assignee

Searches

Searches allow Zapier users to find existing items to use in their Zaps.

Find Project

GET /api/zapier/searches/projects

Required Scope: read:projects

ParameterTypeDescription
querystringSearch by project name
idintegerFind by exact project ID

Find User

GET /api/zapier/searches/users

Required Scope: read:companies

ParameterTypeDescription
querystringSearch by name or email
emailstringFind by exact email