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
- Open Anypoint Studio.
- Navigate to File > New > Mule Project.
- Enter the project name. For example, 'procore-integration'.
- Select Mule Runtime version 4.9.6 or higher.
- 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:
- Run the application in Anypoint Studio.
- Use localhost endpoints for testing.
- Configure local OAuth callback URLs.
- Use the Procore development environment.
CloudHub Deployment
For CloudHub deployment:
- Package your application as a JAR file.
- Deploy the application to CloudHub through Runtime Manager.
- Configure environment-specific properties.
- Set up OAuth callback URLs.
- Configure SSL certificates.
Security Best Practices
Secure Configuration
- Use secure properties for sensitive data.
- Never commit credentials to version control.
- Use environment variables for production.
- Rotate credentials regularly.
OAuth Security
- Use HTTPS for all OAuth endpoints.
- Validate OAuth scopes.
- Implement proper token management.
- Monitor authentication failures.
Input Validation
- Validate all input parameters.
- Sanitize user input.
- Implement proper error handling.
- 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
- Procore API Documentation: developers.procore.com.
- MuleSoft Documentation: docs.mulesoft.com.
- Community Forums: Procore Developer Community.
- Support Tickets: Contact Procore Developer 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. |