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
{
"error": "Bad Request",
"message": "Project name is required"
}
GET API Status
Get API status information including version and your rate limits.
Required Scope: None (public)
Response
{
"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
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
{
"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
Retrieve a paginated list of projects your API key has access to.
Required Scope: read:projects
Query Parameters
| Parameter | Type | Description |
|---|---|---|
| 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
{
"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
Retrieve detailed information about a specific project.
Required Scope: read:projects
Path Parameters
| Parameter | Type | Description |
|---|---|---|
| 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
Create a new project. In sandbox mode, respects sandbox limits.
Required Scope: write:projects
Request Body
| Parameter | Type | Description |
|---|---|---|
| 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
{
"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
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
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
{
"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
List all companies assigned to a project.
Required Scope: read:companies
Response
[
{
"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
List action items (similar to RFIs) for a project.
Required Scope: read:rfis
Query Parameters
| Parameter | Type | Description |
|---|---|---|
| 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
Get details for a specific action item.
Required Scope: read:rfis
GET List Submittals
List submittals for a project.
Required Scope: read:submittals
Query Parameters
| Parameter | Type | Description |
|---|---|---|
| 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
{
"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
Get detailed information about a specific submittal.
Required Scope: read:submittals
GET List Change Orders
List change orders for a project.
Required Scope: read:change_orders
Query Parameters
| Parameter | Type | Description |
|---|---|---|
| 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
{
"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
List daily reports for a project, optionally filtered by date range.
Required Scope: read:daily_logs
Query Parameters
| Parameter | Type | Description |
|---|---|---|
| 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
Create a new daily report for a project.
Required Scope: write:daily_logs
Request Body
| Parameter | Type | Description |
|---|---|---|
| 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
{
"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.
How Webhooks Work
- Configure: Register your webhook endpoint URL in the Developer Portal
- Subscribe: Select which events you want to receive
- Receive: BuildManager Pro sends HTTP POST requests to your endpoint when events occur
- Respond: Return a 2xx status code to acknowledge receipt
Webhook Delivery
- Webhooks are delivered via
HTTP POSTwith a JSON payload - Your endpoint must respond within 30 seconds
- Failed deliveries are retried up to 5 times with exponential backoff
- Retry schedule: 1 min, 5 min, 30 min, 2 hours, 24 hours
Event Types
Subscribe to the events that matter to your integration. All events include the resource data and metadata about the change.
Project Events
| Event | Description |
|---|---|
project.created | A new project was created |
project.updated | Project details were modified |
project.archived | Project was archived |
Daily Report Events
| Event | Description |
|---|---|
daily_report.created | A new daily report was created |
daily_report.published | Daily report was published/finalized |
daily_report.updated | Daily report was modified |
Submittal Events
| Event | Description |
|---|---|
submittal.created | A new submittal was created |
submittal.submitted | Submittal was submitted for review |
submittal.approved | Submittal was approved |
submittal.rejected | Submittal was rejected |
submittal.revised | A revision was uploaded |
RFI Events
| Event | Description |
|---|---|
rfi.created | A new RFI was created |
rfi.answered | RFI received an answer |
rfi.closed | RFI was closed |
Change Order Events
| Event | Description |
|---|---|
change_order.created | A new change order was created |
change_order.submitted | Change order was submitted for approval |
change_order.approved | Change order was approved |
change_order.rejected | Change order was rejected |
Punch List Events
| Event | Description |
|---|---|
punch_item.created | A new punch item was created |
punch_item.completed | Punch item was marked complete |
punch_item.verified | Punch item completion was verified |
Safety Events
| Event | Description |
|---|---|
safety_incident.reported | A safety incident was reported |
safety_observation.created | A 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
{
"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
| Field | Type | Description |
|---|---|---|
| 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:
| Header | Description |
|---|---|
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:
- Get your webhook signing secret from the Developer Portal
- Concatenate the timestamp and request body:
timestamp.body - Compute HMAC-SHA256 using your signing secret
- Compare with the
X-BMP-Signatureheader
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
- Always verify signatures - Never trust webhook data without verification
- Check timestamps - Reject events older than 5 minutes to prevent replay attacks
- Use HTTPS - Always use HTTPS endpoints for your webhook URLs
- Respond quickly - Return 2xx immediately, then process asynchronously
- Handle duplicates - Use the event
idfor idempotency - Store secrets securely - Never commit webhook secrets to version control
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.
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
/api/zapier/me
Use this endpoint to verify your API key is working:
{
"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
/api/zapier/triggers/projects
Triggers when a new project is created or updated.
Required Scope: read:projects
New RFIs
/api/zapier/triggers/rfis
Triggers when a new Request for Information is created.
Required Scope: read:rfis
New Submittals
/api/zapier/triggers/submittals
Triggers when a new submittal is created.
Required Scope: read:submittals
New Change Orders
/api/zapier/triggers/change-orders
Triggers when a new change order is created.
Required Scope: read:change_orders
New Daily Reports
/api/zapier/triggers/daily-reports
Triggers when a new daily report is created.
Required Scope: read:daily_reports
New Punch List Items
/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
/api/zapier/actions/rfis
Required Scope: write:rfis
| Parameter | Type | Required | Description |
|---|---|---|---|
| project_id | integer | Yes | Project ID |
| subject | string | Yes | RFI subject/title |
| question | string | Yes | RFI question/description |
| priority | string | No | low, medium, high (default: medium) |
| due_date | date | No | Due date (YYYY-MM-DD) |
Create Submittal
/api/zapier/actions/submittals
Required Scope: write:submittals
| Parameter | Type | Required | Description |
|---|---|---|---|
| project_id | integer | Yes | Project ID |
| title | string | Yes | Submittal title |
| description | string | No | Submittal description |
| spec_section | string | No | Specification section reference |
| submittal_type | string | No | Type (default: product_data) |
| category | string | No | Category |
| due_date | date | No | Due date (YYYY-MM-DD) |
Create Daily Report
/api/zapier/actions/daily-reports
Required Scope: write:daily_reports
| Parameter | Type | Required | Description |
|---|---|---|---|
| project_id | integer | Yes | Project ID |
| report_date | date | No | Report date (default: today) |
| weather_condition | string | No | Weather conditions |
| temperature | string | No | Temperature |
| work_performed | string | No | Work performed |
| notes | string | No | Additional notes |
| delays | string | No | Any delays encountered |
Create Punch List Item
/api/zapier/actions/punch-list
Required Scope: write:rfis
| Parameter | Type | Required | Description |
|---|---|---|---|
| project_id | integer | Yes | Project ID |
| title | string | Yes | Punch list item title |
| description | string | No | Description |
| location | string | No | Location in project |
| priority | string | No | low, medium, high (default: medium) |
| due_date | date | No | Due date (YYYY-MM-DD) |
| assigned_to_email | string | No | Email of assignee |
Searches
Searches allow Zapier users to find existing items to use in their Zaps.
Find Project
/api/zapier/searches/projects
Required Scope: read:projects
| Parameter | Type | Description |
|---|---|---|
| query | string | Search by project name |
| id | integer | Find by exact project ID |
Find User
/api/zapier/searches/users
Required Scope: read:companies
| Parameter | Type | Description |
|---|---|---|
| query | string | Search by name or email |
| string | Find by exact email |