Stellwerk API Documentation

Authentication

There are two contexts; production access for external clients always uses an API key.

  1. API Key (machine-to-machine / external): Provide an API key via Authorization: Bearer <key> (preferred) or X-API-Key: <key>. The key determines the tenant. This is the public contract.
  2. Session + CSRF (dashboard internal calls only): When the signed-in web dashboard calls the API (same-origin), Rails session + CSRF token are used. This mode is not intended for external automation and requires a browser session. Do not build integrations with this path.

Legacy X-Tenant-ID header based unauthenticated access has been removed—always send an API key outside the dashboard.

Headers

  • X-CSRF-Token: Required for session-based requests from the web app
  • Authorization: Bearer <key> or X-API-Key: Required for machine clients
  • Content-Type: application/json

Endpoints

List Calculations

GET /api/v1/calculations

Query Parameters: - product_id (optional): Filter by product ID - product_code (optional): Filter by product code - template_id (optional): Filter by calculation template ID (only when templates feature is enabled)

Response: json { "calculations": [ { "id": 1, "name": "Stellwerk Calculation", "slug": "flow-rate-calculation", "description": "Calculate flow rate based on input parameters", "product": { "id": 1, "name": "Product Name", "code": "PROD001" }, "ruleset": { "id": 1, "name": "Standard Rules" }, "calculation_template": null, "created_at": "2025-07-08T10:00:00Z", "updated_at": "2025-07-08T10:00:00Z" } ] }

Get Calculation Details

GET /api/v1/calculations/:slug

Response: json { "calculation": { "id": 1, "name": "Stellwerk Calculation", "slug": "flow-rate-calculation", "description": "Calculate flow rate based on input parameters", "product": { "id": 1, "name": "Product Name", "code": "PROD001", "description": "Product description" }, "ruleset": { "id": 1, "name": "Standard Rules", "description": "Standard calculation rules", "rules": [ { "id": 1, "name": "Rule 1", "rule_type": "condition", "conditions": {...}, "actions": {...} } ] }, "calculation_template": null, "created_at": "2025-07-08T10:00:00Z", "updated_at": "2025-07-08T10:00:00Z" } }

Execute Calculation

POST /api/v1/calculations/:slug/execute

Request Body: json { "inputs": { "parameter1": "value1", "parameter2": "value2", "parameter3": "value3" } }

Response: json { "calculation": { "id": 1, "name": "Stellwerk Calculation", "slug": "flow-rate-calculation" }, "inputs": { "parameter1": "value1", "parameter2": "value2" }, "result": { "type": "rule_evaluation", "calculation_id": 1, "calculation_name": "Stellwerk Calculation", "calculation_slug": "flow-rate-calculation", "ruleset": { "id": 1, "name": "Standard Rules" }, "applied_rules": [ { "id": 1, "name": "Start" }, { "id": 3, "name": "Join" }, { "id": 5, "name": "Price" } ], "context": { "parameter1": "value1", "parameter2": "value2", "calculated_result": 150.5, "flow_rate": 100 }, "warnings": [ { "code": "conflicting_end_assignments", "message": "Variable 'price' is assigned in multiple end nodes (2x). Final result is ambiguous.", "details": { "variable": "price", "rule_ids": ["uuid-a", "uuid-b"], "rule_names": ["Compute dynamic price", "Fallback price"] } } ], "execution_status": "success" }, "executed_at": "2025-07-08T10:00:00Z" }

Error Response Example

json
{
  "calculation": {
    "id": 1,
    "name": "Stellwerk Calculation",
    "slug": "flow-rate-calculation"
  },
  "input_data": {
    "parameter1": "value1"
  },
  "result": {
    "type": "error",
    "calculation_id": 1,
    "calculation_name": "Stellwerk Calculation",
    "calculation_slug": "flow-rate-calculation",
    "error_message": "Rule condition error: undefined variable 'missing_param'",
    "execution_status": "failed"
  },
  "executed_at": "2025-07-08T10:00:00Z"
}

Error Responses

400 Bad Request

json
{
  "error": "Input data is required"
}

401 Unauthorized

json
{
  "error": "Authentication required"
}

404 Not Found

json
{
  "error": "Record not found"
}

422 Unprocessable Entity

json
{
  "error": "Validation failed",
  "details": ["Name can't be blank"]
}

Example Usage

cURL Examples

Base URL examples:

  • Production: https://api.flow-rate.io
  • (Your local dev environment may still be http://localhost:3000 but examples below assume production.)

List calculations (API key): bash curl \ -H "Authorization: Bearer $API_KEY" \ -H "Content-Type: application/json" \ https://api.flow-rate.io/api/v1/calculations

Get calculation details (API key): bash curl \ -H "Authorization: Bearer $API_KEY" \ -H "Content-Type: application/json" \ https://api.flow-rate.io/api/v1/calculations/flow-rate-calculation

Execute calculation (API key): bash curl -X POST \ -H "Authorization: Bearer $API_KEY" \ -H "Content-Type: application/json" \ -d '{"inputs":{"flow_rate":100,"pressure":50}}' \ https://api.flow-rate.io/api/v1/calculations/flow-rate-calculation/execute

Notes on Templates (Soft-Hidden)

The Calculation Templates feature is soft-hidden by default. When FEATURE_TEMPLATES is not enabled (default): - The calculation_template object is omitted (null) in API responses. - The template_id filter is ignored. - The evaluator does not merge template schema defaults into the execution context.

When FEATURE_TEMPLATES=true is set, template fields will appear in responses and filtering will be active. The evaluator will merge template schema defaults first (lowest priority), then calculation metadata, then runtime inputs (highest priority).

See the Formula Authoring Guide for projection syntax (items[*].price) and collection functions (sum, count, min, max, first, last, take, map, filter, distinct, average/avg, sumif, countif, trace).