Skip to main content
Procore

MuleSoft - Technical Reference

This technical guide will walk you through how to create and configure MuleSoft projects that integrate with Procore’s construction project management platform. The Procore connector enables enterprise applications to create and manage construction projects through MuleSoft-based solutions.

Version Information

Component Version
Mule Runtime 4.9.6 or higher
Java 17
Connector 0.0.115-SNAPSHOT

Key Features

  • OAuth 2.0 authentication with automatic token refresh.
  • Project creation and management operations.
  • Comprehensive parameter support for project details.
  • Company-specific operations with Procore Company ID.
  • Geographic location support (latitude/longitude).
  • Standard cost code integration.
  • Custom field support.
  • Error handling and logging.

Create a Mule Project

Prerequisites

Before you create a Mule project with the Procore connector, ensure you have the following:

  • MuleSoft Anypoint Studio 7.x or higher.
  • Mule Runtime 4.9.6 or higher.
  • Java 17 or higher.
  • Procore developer account with API access.
  • OAuth 2.0 credentials from Procore.

Project Setup

Create a Mule Project

  1. Open Anypoint Studio.
  2. Navigate to File > NewMule Project.
  3. Enter the project name. For example, 'procore-integration'.
  4. Select Mule Runtime version 4.9.6 or higher.
  5. Click Finish.

Add Procore Connector Dependency

Add the Procore connector dependency to your pom.xml:

<dependency>
 <groupId>com.procore</groupId>
 <artifactId>procore-connector</artifactId>
 <version>0.0.115-SNAPSHOT</version>
 <classifier>mule-plugin</classifier>
</dependency>

Configure Project Properties

Create a src/main/resources/properties/dev.properties file :

# HTTP Listener Configuration
http.listener.host=0.0.0.0
http.listener.port=8081

# Procore OAuth Configuration
procore.config.oauth.consumer_key=your-consumer-key
procore.config.oauth.consumer_secret=your-consumer-secret
procore.config.oauth.callback_path=/mule/callback
procore.config.oauth.authorize_path=/authorize-procore
procore.config.oauth.external_callback_path=http://localhost:8081/mule/callback

Project Configuration

HTTP Listener Configuration

Configure the HTTP listener for your Mule application:

<http:listener-config name="HTTP_Listener_config" doc:name="HTTP Listener config">
 <http:listener-connection host="${http.listener.host}" port="${http.listener.port}"
/>
</http:listener-config>

Procore Connector Configuration

Configure the Procore connector with OAuth 2.0 authentication:

<procore:config name="Procore_Config" doc:name="Procore Config">
 <procore:connection>
 <procore:oauth-authorization-code
 consumerKey="${procore.config.oauth.consumer_key}"
 consumerSecret="${procore.config.oauth.consumer_secret}"/>
 <procore:oauth-callback-config
 listenerConfig="HTTP_Listener_config"
 callbackPath="${procore.config.oauth.callback_path}"
 authorizePath="${procore.config.oauth.authorize_path}"
 externalCallbackUrl="${procore.config.oauth.external_callback_path}" />
 </procore:connection>
</procore:config>

Environment-Specific Configuration

Create separate property files for different environments:

Development Environment (dev.properties)

http.listener.host=0.0.0.0
http.listener.port=8081
procore.config.oauth.external_callback_path=http://localhost:8081/mule/callback

Staging Environment (staging.properties)

http.listener.host=0.0.0.0
http.listener.port=8081
procore.config.oauth.external_callback_path=https://staging.yourdomain.com/mule/callback

Production Environment (prod.properties)

http.listener.host=0.0.0.0
http.listener.port=8081
procore.config.oauth.external_callback_path=https://yourdomain.com/mule/callback

Create a Mule Flow

Basic Project Creation Flow

Create a flow to handle project creation requests:

<flow name="createProjectFlow">
 <http:listener config-ref="HTTP_Listener_config" path="/create-project"/>
 
 <!-- Validate input payload -->
 <validation:is-not-null value="#[payload.company_id]" message="Company ID is
required"/>
 <validation:is-not-null value="#[payload.name]" message="Project name is required"/>
 
 <!-- Transform payload if needed -->
 <ee:transform>
 <ee:message>
 <ee:set-payload><![CDATA[%dw 2.0
output application/java
---
{
 companyId: payload.company_id,
 name: payload.name,
 address: payload.address,
 city: payload.city,
 stateCode: payload.state_code,
 countryCode: payload.country_code,
 zip: payload.zip,
 description: payload.description,
 startDate: payload.start_date,
 completionDate: payload.completion_date,
 totalValue: payload.total_value
}]]></ee:set-payload>
 </ee:message>
 </ee:transform>
 
 <!-- Call Procore API -->
 <procore:create-project config-ref="Procore_Config"
 companyId="#[payload.companyId]"
 name="#[payload.name]"
 address="#[payload.address]"
 city="#[payload.city]"
 stateCode="#[payload.stateCode]"
 countryCode="#[payload.countryCode]"
 zip="#[payload.zip]"
 description="#[payload.description]"
 startDate="#[payload.startDate]"
 completionDate="#[payload.completionDate]"
 totalValue="#[payload.totalValue]"/>
 
 <!-- Handle response -->
 <ee:transform>
 <ee:message>
 <ee:set-payload><![CDATA[%dw 2.0
output application/json
---
{
 success: true,
 projectId: payload.id,
 projectName: payload.name,
 message: "Project created successfully"
}]]></ee:set-payload>
 </ee:message>
 </ee:transform>
</flow>

Project Update Flow

Create a flow to handle project updates:

<flow name="updateProjectFlow">
 <http:listener config-ref="HTTP_Listener_config" path="/update-project"/>
 
 <!-- Validate required parameters -->
 <validation:is-not-null value="#[payload.project_id]" message="Project ID is
required"/>
 <validation:is-not-null value="#[payload.company_id]" message="Company ID is
required"/>
 
 <!-- Call Procore API -->
 <procore:update-project config-ref="Procore_Config"
 companyId="#[payload.company_id]"
 projectId="#[payload.project_id]"
 name="#[payload.name]"
 active="#[payload.active]"
 address="#[payload.address]"
 city="#[payload.city]"
 description="#[payload.description]"
 startDate="#[payload.start_date]"
 completionDate="#[payload.completion_date]"
 totalValue="#[payload.total_value]"/>
 
 <!-- Handle response -->
 <ee:transform>
 <ee:message>
 <ee:set-payload><![CDATA[%dw 2.0
output application/json
---
{
 success: true,
 projectId: payload.id,
 projectName: payload.name,
 message: "Project updated successfully"
}]]></ee:set-payload>
 </ee:message>
 </ee:transform>
</flow>

Error Handling Flow

Create a global error handler for your application:

<error-handler name="GlobalErrorHandler">
 <on-error-continue type="PROCORE:BAD_REQUEST">
 <ee:transform>
 <ee:message>
 <ee:set-payload><![CDATA[%dw 2.0
output application/json
---
{
 success: false,
 error: "Bad Request",
 message: error.description,
 details: error.detailedDescription
}]]></ee:set-payload>
 </ee:message>
 </ee:transform>
 <http:response-builder statusCode="400"/>
 </on-error-continue>
 
 <on-error-continue type="PROCORE:UNAUTHORIZED">
 <ee:transform>
 <ee:message>
 <ee:set-payload><![CDATA[%dw 2.0
output application/json
---
{
 success: false,
 error: "Unauthorized",
 message: "Invalid or expired authentication credentials"
}]]></ee:set-payload>
 </ee:message>
 </ee:transform>
 <http:response-builder statusCode="401"/>
 </on-error-continue>
 
 <on-error-continue type="PROCORE:FORBIDDEN">
 <ee:transform>
 <ee:message>
 <ee:set-payload><![CDATA[%dw 2.0
output application/json
---
{
 success: false,
 error: "Forbidden",
 message: "Insufficient permissions to access the resource"
}]]></ee:set-payload>
 </ee:message>
 </ee:transform>
 <http:response-builder statusCode="403"/>
 </on-error-continue>
 
 <on-error-continue type="PROCORE:NOT_FOUND">
 <ee:transform>
 <ee:message>
 <ee:set-payload><![CDATA[%dw 2.0
output application/json
---
{
 success: false,
 error: "Not Found",
 message: "The requested resource was not found"
}]]></ee:set-payload>
 </ee:message>
 </ee:transform>
 <http:response-builder statusCode="404"/>
 </on-error-continue>
 
 <on-error-continue type="ANY">
 <ee:transform>
 <ee:message>
 <ee:set-payload><![CDATA[%dw 2.0
output application/json
---
{
 success: false,
 error: "Internal Server Error",
 message: "An unexpected error occurred"
}]]></ee:set-payload>
 </ee:message>
 </ee:transform>
 <http:response-builder statusCode="500"/>
 </on-error-continue>
</error-handler>

DataWeave Transformations

Input Validation Transformation

Create a DataWeave transformation to validate and transform input data:

<ee:transform>
 <ee:message>
 <ee:set-payload><![CDATA[%dw 2.0
output application/java
---
{
 companyId: payload.company_id default "",
 name: payload.name default "",
 address: payload.address default "",
 city: payload.city default "",
 stateCode: payload.state_code default "",
 countryCode: payload.country_code default "US",
 zip: payload.zip default "",
 description: payload.description default "",
 startDate: payload.start_date default "",
 completionDate: payload.completion_date default "",
 totalValue: payload.total_value default 0.0,
 latitude: payload.latitude default "",
 longitude: payload.longitude default "",
 phone: payload.phone default "",
 projectNumber: payload.project_number default "",
 active: payload.active default true
}]]></ee:set-payload>
 </ee:message>
</ee:transform>

Response Transformation

Create a DataWeave transformation for API responses:

<ee:transform>
 <ee:message>
 <ee:set-payload><![CDATA[%dw 2.0
output application/json
---
{
 success: true,
 data: {
 id: payload.id,
 name: payload.name,
 description: payload.description,
 active: payload.active,
 address: payload.address,
 city: payload.city,
 stateCode: payload.stateCode,
 countryCode: payload.countryCode,
 zip: payload.zip,
 startDate: payload.startDate,
 completionDate: payload.completionDate,
 totalValue: payload.totalValue,
 createdAt: payload.createdAt,
 updatedAt: payload.updatedAt
 },
 message: "Operation completed successfully"
}]]></ee:set-payload>
 </ee:message>
</ee:transform>

Deployment

Local Development

For local development:

  1. Run the application in Anypoint Studio.
  2. Use localhost endpoints for testing.
  3. Configure local OAuth callback URLs.
  4. Use the Procore development environment.

CloudHub Deployment

For CloudHub deployment:

  1. Package your application as a JAR file.
  2. Deploy the application to CloudHub through Runtime Manager.
  3. Configure environment-specific properties.
  4. Set up OAuth callback URLs.
  5. Configure SSL certificates.

Security Best Practices

Secure Configuration

  1. Use secure properties for sensitive data.
  2. Never commit credentials to version control.
  3. Use environment variables for production.
  4. Rotate credentials regularly.

OAuth Security

  1. Use HTTPS for all OAuth endpoints.
  2. Validate OAuth scopes.
  3. Implement proper token management.
  4. Monitor authentication failures.

Input Validation

  1. Validate all input parameters.
  2. Sanitize user input.
  3. Implement proper error handling.
  4. Log security events.

Troubleshooting

Common Issues

Authentication Problems

ISSUE SOLUTION
UNAUTHORIZED Error Check the consumer key and secret key for OAuth.
ACCESS_TOKEN_MISSING Verify the configuration for token refresh.
OAUTH_STATE_MISSING Ensure that the OAuth flow is configured correctly.
Scope Issues Ensure that the requested scope is authorized.

API Errors

ERROR SOLUTION
BAD_REQUEST  Check the required parameters and data types.
INVALID_REQUEST  Verify the format and structure of the request.
FORBIDDEN  Verify that the user has the required permissions.
TOO_MANY_REQUESTS  Implement the correct retry logic with exponential backoff.

Resource Errors

ERROR SOLUTION
NOT_FOUND  Verify that the project or company ID exists and is accessible.
CONFLICT  Verify the state of the resource before initiating update operations.
UNPROCESSABLE_ENTITY  Check the validation rules of the business logic.

Connection Issues

ERROR SOLUTION
CONNECTIVITY  Check the network connectivity and firewall settings.
SERVICE_UNAVAILABLE  Procore service may be temporarily down.
REQUEST_TIMEOUT  Increase the timeout settings.
GATEWAY_TIMEOUT  Check the configuration of the proxy or load balancer.

Debugging

Enable Debug Logging

<logger name="com.procore.mule" level="DEBUG"/>

Common Debug Information

  • Request/Response Logs: Log API request and response details.
  • Token Information: Log token refresh events and OAuth state.
  • Parameter Validation: Log parameter validation results.
  • Error Details: Log detailed error information with Procore error types.
  • Connection Events: Log connection creation and failure events.

Support

Best Practices

Development

  • Use Secure Properties: Store sensitive configuration in secure properties.
  • Implement Error Handling: Always implement proper error handling.
  • Validate Input: Validate all input parameters before API calls.
  • Log Operations: Log operation attempts for debugging.
  • Test Thoroughly: Test all operations with various parameter combinations.

Production

  • Monitor Performance: Monitor API response times and error rates.
  • Implement Retry Logic: Implement retry logic for transient errors.
  • Use Connection Pooling: Leverage connection pooling for better performance.
  • Secure Configuration: Use secure properties for sensitive data.
  • Regular Updates: Keep the connector updated to the latest version.

Testing

  • Unit Tests: Write unit tests for all operations.
  • Integration Tests: Test with the actual Procore API.
  • Error Scenarios: Test error handling scenarios.
  • Performance Tests: Test with realistic data volumes.
  • Security Tests: Test authentication and authorization.

Appendix

API Endpoints

OPERATION METHOD ENDPOINT DESCRIPTION
Create Project POST /rest/v1.0/projects Create a new project
Update Project PATCH /rest/v1.0/projects/{id} Update an existing project

Procore Error Codes

ERROR CODE DESCRIPTION CAUSE SOLUTION
BAD_REQUEST Invalid request parameters or malformed data. Missing required fields or invalid data types. Check the request payload and validate parameters.
UNAUTHORIZED Invalid or expired authentication credentials. Invalid OAuth tokens or expired access tokens. Refresh the OAuth tokens or re-authenticate.
FORBIDDEN Insufficient permissions to access the resource. The user lacks the required permissions. Verify user permissions in Procore.
NOT_FOUND The requested resource was not found.  Invalid project or company ID or deleted resource. Verify that the resource exists and is accessible.
REQUEST_TIMEOUT The request timed out. Network latency or server overload. Implement retry logic with backoff.
CONFLICT The request conflicts with the current state of the resource. Concurrent modifications or business rule violations. Check the resource state before updating.
UNPROCESSABLE_ENTITY Well-formed request with semantic errors. Validation failures of the business logic. Review business rules and data constraints.
TOO_MANY_REQUESTS Rate limit exceeded. API rate limiting. Implement exponential backoff retry.
INTERNAL_SERVER_ERROR Unexpected error on Procore server.  Server-side issues. Contact Procore support.
NOT_IMPLEMENTED Requested operation is not supported.  API endpoint is unavailable. Check the API documentation for supported operations.
BAD_GATEWAY Gateway error. Proxy or load balancer issues. Check the network infrastructure.
SERVICE_UNAVAILABLE Procore service is temporarily unavailable. Maintenance or server issues. Retry after the service is restored.
GATEWAY_TIMEOUT  Gateway timeout. Network timeout issues. Increase the timeout settings.
HTTP_VERSION_NOT_SUPPORTED  Unsupported HTTP version. Protocol version mismatch. Use a supported HTTP version.
CONNECTIVITY Unable to connect to Procore services. Network issues or firewall blocking. Check the network connectivity.
INVALID_REQUEST Request contains invalid parameters or format. Malformed request structure. Validate the request format.
UNEXPECTED_ERROR Unexpected error occurred. Unknown or unclassified errors. Check logs for detailed information on the error.

Data Types

TYPE DESCRIPTION EXAMPLE
String  Text values "Project Name"
Boolean True/false values true
Double Decimal numbers 1000000.0
Integer Whole numbers 50000
List Array of strings ["dept1", "dept2"]
Date Date values "2024-01-01"

Glossary

TERM DEFINITION
Procore Construction project management platform.
OAuth 2.0 Authorization protocol for secure API access.
Company ID Unique identifier for a Procore company.
Project ID Unique identifier for a Procore project.
Standard Cost Codes Predefined cost categories for construction projects.
Custom Fields User-defined fields for project customization.
Procore Error Codes Specific error types that are defined by the Procore connector for error handling.
BAD_REQUEST Error indicating invalid request parameters or malformed data.
UNAUTHORIZED Error indicating invalid or expired authentication credentials.
FORBIDDEN Error indicating insufficient permissions to access a resource.
NOT_FOUND Error indicating the requested resource was not found.
CONFLICT Error indicating request conflicts with current resource state.
TOO_MANY_REQUESTS Error indicating API rate limit has been exceeded.
CONNECTIVITY Error indicating inability to connect to Procore services.
UNEXPECTED_ERROR Generic error for unknown or unclassified errors.