Skip to main content

Execute API

The Execute API triggers business rule evaluation for a specific entity. Use this endpoint to manually execute rules, test rule logic, or integrate rule execution into custom workflows.

Environment Setup​

export BASE_URL="http://localhost:3000"
export API_KEY="your_api_key_here"

Execute Rules​

Execute all applicable rules for an entity.

POST /api/business_rules/execute​

Feature Required: business_rules.rules.execute

Request Body:

{
entityType: string // Required: Entity type (e.g., "Order", "WorkOrder")
entityId?: string // Optional: Specific entity ID
eventType?: string // Optional: Lifecycle event (e.g., "beforeCreate", "afterUpdate")
data: object // Required: Entity data for evaluation
dryRun?: boolean // Optional: Preview without side effects (default: false)
}

Parameters Explained:

  • entityType: The type of entity being evaluated. Must match a rule's entityType to be considered.
  • entityId: Optional identifier for the specific entity instance. Used for logging and tracking.
  • eventType: Optional lifecycle event that triggered execution. Rules filter by this field.
  • data: The entity data object containing fields referenced in rule conditions.
  • dryRun: When true, rules are evaluated but actions with external side effects (webhooks, notifications) may still execute. Use for testing.

Example Request:

curl -X POST "$BASE_URL/api/business_rules/execute" \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"entityType": "Order",
"entityId": "order-12345",
"eventType": "beforeCreate",
"data": {
"orderId": "order-12345",
"total": 15000,
"customerId": "customer-789",
"status": "PENDING",
"items": [
{"productId": "prod-1", "quantity": 10, "price": 1500}
]
},
"dryRun": false
}'

Example Response (200 OK):

{
"allowed": true,
"executedRules": [
{
"ruleId": "LARGE_ORDER_APPROVAL",
"ruleName": "Require Approval for Large Orders",
"result": "SUCCESS",
"conditionResult": true,
"executionTime": 12,
"actionsExecuted": ["SET_FIELD", "NOTIFY"]
},
{
"ruleId": "ORDER_VALIDATION",
"ruleName": "Validate Order Data",
"result": "SUCCESS",
"conditionResult": true,
"executionTime": 8,
"actionsExecuted": ["LOG"]
}
],
"totalExecutionTime": 20,
"errors": [],
"logIds": [
"log-uuid-1",
"log-uuid-2"
]
}

Response Fields:

  • allowed: Boolean indicating if the operation should proceed. False if any GUARD rule blocked it.
  • executedRules: Array of rules that were evaluated, with results and timing.
  • totalExecutionTime: Total time in milliseconds for all rule execution.
  • errors: Array of error messages if any rules failed to execute.
  • logIds: Array of execution log IDs for audit trail.

Response Scenarios​

All Rules Pass​

{
"allowed": true,
"executedRules": [
{
"ruleId": "VALIDATION_RULE",
"result": "SUCCESS",
"conditionResult": true,
"executionTime": 10
}
],
"totalExecutionTime": 10,
"errors": [],
"logIds": ["log-1"]
}

The operation is allowed to proceed. All rules passed successfully.

GUARD Rule Blocks Operation​

{
"allowed": false,
"executedRules": [
{
"ruleId": "MATERIAL_AVAILABILITY_CHECK",
"result": "FAILURE",
"conditionResult": true,
"executionTime": 15,
"actionsExecuted": ["BLOCK_TRANSITION", "SHOW_ERROR", "NOTIFY"],
"message": "Cannot release work order. Required materials are not available."
}
],
"totalExecutionTime": 15,
"errors": [],
"logIds": ["log-1"]
}

The operation is blocked. A GUARD rule's conditions were true, triggering failure actions that blocked the transition.

Rule Execution Error​

{
"allowed": true,
"executedRules": [
{
"ruleId": "BROKEN_RULE",
"result": "ERROR",
"conditionResult": null,
"executionTime": 5,
"error": "Invalid field path: nonexistent.field"
}
],
"totalExecutionTime": 5,
"errors": ["Rule BROKEN_RULE failed: Invalid field path"],
"logIds": ["log-1"]
}

A rule encountered an error during execution. Other rules may still have executed. Check the errors array and execution logs.

No Applicable Rules​

{
"allowed": true,
"executedRules": [],
"totalExecutionTime": 0,
"errors": [],
"logIds": []
}

No rules matched the entity type and event type criteria. The operation proceeds without rule evaluation.

Dry Run Mode​

Dry run mode evaluates rules without committing changes. Use this to test rules before enabling them in production.

Enable Dry Run:

curl -X POST "$BASE_URL/api/business_rules/execute" \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"entityType": "WorkOrder",
"entityId": "wo-test-123",
"data": {"status": "RELEASED", "materialsAvailable": false},
"dryRun": true
}'

Dry Run Behavior:

  • ✅ Conditions are evaluated normally
  • ✅ Execution is logged
  • ✅ Response indicates what would happen
  • ⚠️ Some actions may still execute (webhooks, external calls)
  • ❌ Database updates (SET_FIELD) are not committed
  • ❌ Internal events (EMIT_EVENT) are not emitted

⚠️ Important: CALL_WEBHOOK and NOTIFY actions may still execute in dry run mode. Be cautious when testing rules with external integrations.

Rule Discovery​

The engine automatically discovers applicable rules based on:

  1. Entity Type Match: Rule's entityType matches request's entityType
  2. Event Type Match: Rule's eventType is empty OR matches request's eventType
  3. Enabled Status: Rule's enabled is true
  4. Effective Dates: Current date is within rule's effectiveFrom and effectiveTo range
  5. Tenant Scope: Rule belongs to the same tenant/organization

Execution Order: Rules execute in priority order (highest first). Within the same priority, order is deterministic but not guaranteed.

Common Workflows​

Validate Before Save​

# Validate order data before creation
response=$(curl -s -X POST "$BASE_URL/api/business_rules/execute" \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"entityType": "Order",
"eventType": "beforeCreate",
"data": {
"total": 15000,
"customerId": "cust-123"
},
"dryRun": false
}')

allowed=$(echo "$response" | jq -r '.allowed')

if [ "$allowed" = "true" ]; then
echo "Validation passed, creating order..."
# Proceed with order creation
else
echo "Validation failed:"
echo "$response" | jq -r '.executedRules[] | select(.result == "FAILURE") | .message'
# Abort order creation
fi

Test Rule Logic​

# Test a rule with sample data
curl -X POST "$BASE_URL/api/business_rules/execute" \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"entityType": "WorkOrder",
"eventType": "onStatusChange",
"data": {
"id": "test-wo-1",
"oldStatus": "PENDING",
"newStatus": "RELEASED",
"materialsAvailable": true,
"assignedTo": "user-123"
},
"dryRun": true
}' | jq

Bulk Entity Validation​

# Validate multiple entities
for entity in entity1.json entity2.json entity3.json; do
echo "Validating $entity..."
response=$(curl -s -X POST "$BASE_URL/api/business_rules/execute" \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d @"$entity")

allowed=$(echo "$response" | jq -r '.allowed')
if [ "$allowed" != "true" ]; then
echo " FAILED: $entity"
echo "$response" | jq '.executedRules[] | select(.result == "FAILURE")'
else
echo " PASSED: $entity"
fi
done

Integration with Workflows​

// TypeScript/Node.js example
import fetch from 'node-fetch'

async function validateWorkOrderRelease(workOrder) {
const response = await fetch(`${process.env.BASE_URL}/api/business_rules/execute`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.API_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
entityType: 'WorkOrder',
entityId: workOrder.id,
eventType: 'onStatusChange',
data: {
...workOrder,
oldStatus: workOrder.status,
newStatus: 'RELEASED'
},
dryRun: false
})
})

const result = await response.json()

if (!result.allowed) {
const blockingRule = result.executedRules.find(r => r.result === 'FAILURE')
throw new Error(blockingRule?.message || 'Work order release blocked by business rules')
}

return result
}

Performance Considerations​

Rule Count: Execution time scales with the number of applicable rules. Monitor execution logs for slow rules.

Complex Conditions: Deeply nested conditions or regex patterns can increase evaluation time.

Actions: External actions (webhooks) execute asynchronously but may impact overall performance.

Timeouts: Rules have execution timeouts to prevent runaway execution:

  • Per-rule timeout: 5 seconds
  • Total execution timeout: 30 seconds

Best Practices:

  • Use specific eventType to reduce the number of rules evaluated
  • Prioritize critical rules (higher priority) to execute first
  • Monitor execution logs and optimize slow rules
  • Consider rule set organization for better performance

Error Handling​

Invalid Entity Type (400 Bad Request):

{
"error": "entityType is required"
}

Missing Data (400 Bad Request):

{
"error": "data object is required"
}

Rule Evaluation Error:

Even if a rule fails, the response is 200 OK. Check the errors array:

{
"allowed": true,
"executedRules": [...],
"errors": [
"Rule BROKEN_RULE failed: Field path error"
],
...
}

Permission Denied (403 Forbidden):

{
"error": "Insufficient permissions",
"required": ["business_rules.rules.execute"]
}

Integration Patterns​

Pre-Save Validation​

Execute rules before database writes:

app.post('/api/orders', async (req, res) => {
const orderData = req.body

// Execute validation rules
const ruleResult = await executeRules({
entityType: 'Order',
eventType: 'beforeCreate',
data: orderData
})

if (!ruleResult.allowed) {
return res.status(400).json({
error: 'Validation failed',
details: ruleResult.executedRules
.filter(r => r.result === 'FAILURE')
.map(r => r.message)
})
}

// Proceed with order creation
const order = await db.orders.create(orderData)
res.json(order)
})

Post-Save Actions​

Execute rules after successful saves:

app.patch('/api/work-orders/:id/status', async (req, res) => {
const { newStatus } = req.body
const workOrder = await db.workOrders.findById(req.params.id)

// Update status
workOrder.status = newStatus
await workOrder.save()

// Execute post-update rules (notifications, webhooks)
await executeRules({
entityType: 'WorkOrder',
entityId: workOrder.id,
eventType: 'afterUpdate',
data: {
...workOrder.toJSON(),
oldStatus: workOrder.previousStatus,
newStatus: newStatus
}
})

res.json(workOrder)
})

Background Processing​

Execute rules asynchronously for non-blocking operations:

import { queue } from './queue'

// Queue rule execution
queue.add('execute-rules', {
entityType: 'Order',
entityId: order.id,
eventType: 'afterCreate',
data: order
})

// Process in worker
queue.process('execute-rules', async (job) => {
const result = await executeRules(job.data)
console.log(`Rules executed for ${job.data.entityId}:`, result)
})

Debugging​

Enable Verbose Logging:

Review execution logs for detailed information:

# Execute rule
result=$(curl -s -X POST "$BASE_URL/api/business_rules/execute" -d '...')

# Get log IDs
logIds=$(echo "$result" | jq -r '.logIds[]')

# Fetch detailed logs
for logId in $logIds; do
curl -s -X GET "$BASE_URL/api/business_rules/logs/$logId" \
-H "Authorization: Bearer $API_KEY" | jq
done

Common Issues:

  • No rules executed: Check entity type, event type, and enabled status
  • Unexpected results: Review condition logic in execution logs
  • Timeout errors: Simplify conditions or reduce rule count
  • Field path errors: Verify field paths exist in entity data

Next Steps​