Skip to main content
POST
/
api
/
v1
/
pricing
/
analysis
Optimal Configuration Search
curl --request POST \
  --url https://api.example.com/api/v1/pricing/analysis \
  --header 'Content-Type: application/json' \
  --data '
{
  "operation": "<string>",
  "solver": "<string>",
  "objective": "<string>",
  "filters": "<string>"
}
'
{
  "jobId": "<string>",
  "status": "<string>",
  "submittedAt": "<string>",
  "startedAt": "<string>",
  "completedAt": "<string>",
  "result": {
    "result.optimal": {
      "result.optimal.subscriptions": [
        {
          "result.optimal.subscriptions[].plan": "<string>",
          "result.optimal.subscriptions[].addOns": [
            "<string>"
          ],
          "result.optimal.subscriptions[].features": [
            "<string>"
          ],
          "result.optimal.subscriptions[].usageLimits": [
            {}
          ],
          "result.optimal.subscriptions[].cost": "<string>"
        }
      ],
      "result.optimal.cost": 123
    }
  }
}
The Optimal Configuration operation uses constraint satisfaction programming to find the best subscription configurations according to specific optimization criteria. This is useful for recommending configurations to customers or analyzing pricing model efficiency.

Overview

The optimal operation analyzes all valid configurations in your pricing model and returns the one(s) that best match your criteria:
  • Minimize cost: Find the cheapest configuration that meets requirements
  • Maximize cost: Find the most expensive/feature-rich configuration
  • Custom constraints: Apply filters for features, usage limits, and price ranges
Only the MiniZinc solver currently supports the optimal operation. The Choco solver implementation is planned for a future release.

Request

POST /api/v1/pricing/analysis

Parameters

pricingFile
file
required
The YAML file containing the pricing configuration
operation
string
required
Must be optimal
solver
string
required
Must be minizinc
objective
string
required
The optimization objective:
  • minimize - Find lowest-cost configuration
  • maximize - Find highest-cost configuration
filters
string
Optional JSON string with filter criteria to constrain the search space.Filter Fields:
  • minPrice (number): Minimum acceptable price
  • maxPrice (number): Maximum acceptable price
  • maxSubscriptionSize (number): Maximum number of items (plan + add-ons)
  • features (string[]): Required features that must be included
  • usageLimits (object[]): Required usage limit values
Example:
{
  "maxPrice": 50,
  "features": ["gitIntegration", "realTimeTrackChanges"],
  "usageLimits": [
    {"name": "maxCollaboratorsPerProject", "value": 5}
  ]
}

Example Requests

curl -X POST "http://localhost:3000/api/v1/pricing/analysis" \
  -F "[email protected]" \
  -F "operation=optimal" \
  -F "solver=minizinc" \
  -F "objective=minimize" \
  -F 'filters={"features": ["gitIntegration"]}'

Response

The endpoint returns a job ID immediately (202 Accepted). Poll the job status endpoint to get results.

Initial Response (202 Accepted)

{
  "jobId": "job-optimal-a1b2c3d4",
  "status": "PENDING",
  "submittedAt": "2026-03-05T15:30:00Z"
}

Completed Job Response (200 OK)

Once the job completes, the result contains the optimal configuration:
jobId
string
required
Job identifier
status
string
required
Job status: COMPLETED
submittedAt
string
required
ISO 8601 timestamp of job submission
startedAt
string
required
ISO 8601 timestamp of when processing started
completedAt
string
required
ISO 8601 timestamp of completion
result
object
required
The optimization result
result.optimal
object
required
The optimal configuration found
result.optimal.subscriptions
array
required
Array of subscription configurations (typically contains one item for single-subscription optimization)
result.optimal.subscriptions[].plan
string
required
Name of the selected plan
result.optimal.subscriptions[].addOns
string[]
required
List of add-on names included in the configuration
result.optimal.subscriptions[].features
string[]
List of feature names included (available when using MiniZinc)
result.optimal.subscriptions[].usageLimits
object[]
Usage limits and their values in this configuration
result.optimal.subscriptions[].cost
string
Total cost formatted with currency (e.g., “21 USD”)
result.optimal.cost
number
required
Numeric total cost of the optimal configuration

Example: Minimize Cost Result

{
  "jobId": "job-optimal-a1b2c3d4",
  "status": "COMPLETED",
  "submittedAt": "2026-03-05T15:30:00Z",
  "startedAt": "2026-03-05T15:30:02Z",
  "completedAt": "2026-03-05T15:30:08Z",
  "result": {
    "optimal": {
      "subscriptions": [
        {
          "plan": "FREE",
          "addOns": [],
          "features": [
            "latexEditor",
            "realTimeCollaboration",
            "projects",
            "templates",
            "fastCompileServers"
          ],
          "usageLimits": [
            {
              "name": "maxCollaboratorsPerProject",
              "value": 1
            },
            {
              "name": "compileTimeoutLimit",
              "value": 1
            }
          ],
          "cost": "0 USD"
        }
      ],
      "cost": 0
    }
  }
}

Example: Maximize Features Result

{
  "jobId": "job-optimal-x9y8z7w6",
  "status": "COMPLETED",
  "submittedAt": "2026-03-05T16:00:00Z",
  "startedAt": "2026-03-05T16:00:02Z",
  "completedAt": "2026-03-05T16:00:12Z",
  "result": {
    "optimal": {
      "subscriptions": [
        {
          "plan": "STANDARD",
          "addOns": [],
          "features": [
            "latexEditor",
            "realTimeCollaboration",
            "projects",
            "templates",
            "fastestCompileServers",
            "realTimeTrackChanges",
            "fullDocumentHistory",
            "advancedReferenceSearch",
            "gitIntegration",
            "symbolPalette",
            "githubIntegration",
            "dropboxIntegration",
            "mendeleyIntegration",
            "zoteroIntegration",
            "prioritySupport"
          ],
          "usageLimits": [
            {
              "name": "maxCollaboratorsPerProject",
              "value": 11
            },
            {
              "name": "compileTimeoutLimit",
              "value": 4
            }
          ],
          "cost": "21 USD"
        }
      ],
      "cost": 21
    }
  }
}

Use Cases

Build a recommendation system that suggests the best plan to customers based on their requirements.
async function recommendPlan(requirements) {
  const { features, maxBudget } = requirements;
  
  // Find cheapest plan with required features
  const formData = new FormData();
  formData.append('pricingFile', await loadPricingFile());
  formData.append('operation', 'optimal');
  formData.append('solver', 'minizinc');
  formData.append('objective', 'minimize');
  formData.append('filters', JSON.stringify({
    maxPrice: maxBudget,
    features: features
  }));
  
  const job = await createJob(formData);
  const result = await waitForJob(job.jobId);
  
  return result.optimal.subscriptions[0];
}
Identify price gaps in your pricing model by finding configurations with similar features but different costs.
# Find minimum cost for a feature set
min_config = get_optimal(features=['feature1', 'feature2'], objective='minimize')

# Find maximum cost for same features  
max_config = get_optimal(features=['feature1', 'feature2'], objective='maximize')

gap = max_config['cost'] - min_config['cost']
print(f"Price range for these features: ${gap}")
Compare your pricing against competitors by finding equivalent configurations.
competitor_features = ['git', 'cicd', 'support']

our_optimal = get_optimal(
    pricing_file='our-pricing.yaml',
    filters={'features': competitor_features},
    objective='minimize'
)

print(f"Our price for competitor's feature set: ${our_optimal['cost']}")
print(f"Competitor price: $49")
Find the minimal upgrade path when a customer needs additional features.
async function findUpgradePath(currentPlan, newFeatures) {
  // Get current features
  const current = await getPlanDetails(currentPlan);
  const allRequiredFeatures = [...current.features, ...newFeatures];
  
  // Find cheapest plan with all features
  const optimal = await getOptimal({
    features: allRequiredFeatures,
    objective: 'minimize'
  });
  
  const upgradeCost = optimal.cost - current.price;
  return { targetPlan: optimal.plan, cost: upgradeCost };
}

Filter Criteria Details

Price Filters

{
  "minPrice": 10,
  "maxPrice": 50
}
Constrains the solution space to configurations within the specified price range.

Feature Requirements

{
  "features": ["gitIntegration", "realTimeTrackChanges", "prioritySupport"]
}
The optimal configuration MUST include all specified features. Feature names must exactly match those defined in your pricing YAML.

Usage Limit Requirements

{
  "usageLimits": [
    {"name": "maxCollaboratorsPerProject", "value": 10},
    {"name": "compileTimeoutLimit", "value": 4}
  ]
}
The optimal configuration MUST meet or exceed the specified usage limit values.

Subscription Size Limit

{
  "maxSubscriptionSize": 3
}
Limits the total number of items (1 plan + N add-ons) in the configuration. Useful for:
  • Keeping configurations simple
  • Reducing management overhead
  • Limiting billing complexity
Example: maxSubscriptionSize: 3 means maximum of 1 plan + 2 add-ons.

Performance Considerations

Execution Time

Optimization job duration depends on:
  • Model complexity: Number of plans, add-ons, features
  • Filter constraints: More constraints = faster solving
  • Configuration space size: Larger spaces take longer
Typical execution times:
Model SizeAvg. TimeMax Time
Small (2-5 plans, fewer than 10 add-ons)2-5s10s
Medium (5-10 plans, 10-30 add-ons)5-15s30s
Large (10+ plans, 30+ add-ons)15-45s60s
Very large configuration spaces (1000+ valid combinations) may exceed the default 30s solver timeout. Consider adding more filter constraints to reduce the search space.

Optimization Tips

  1. Add constraints: More filters = faster solving
  2. Use specific features: Narrow the solution space
  3. Set price bounds: Eliminate large portions of search space
  4. Limit subscription size: Reduce combinatorial explosion

Error Handling

No Feasible Solution

If no configuration satisfies all constraints:
{
  "jobId": "job-123",
  "status": "COMPLETED",
  "result": {
    "error": "No feasible solution found: No configuration meets all filter criteria"
  }
}

Solver Timeout

{
  "jobId": "job-456",
  "status": "FAILED",
  "failedAt": "2026-03-05T15:30:35Z",
  "error": {
    "message": "Solver timeout after 30s",
    "details": "Consider adding more filter constraints to reduce search space"
  }
}

Implementation

The optimal operation is implemented in:
  • Job creation: /home/daytona/workspace/source/analysis_api/src/api/analysis.ts:289
  • MiniZinc solver integration: /home/daytona/workspace/source/analysis_api/src/services/minizinc.service.ts

Subscriptions

Enumerate all valid configurations instead of just the optimal one

Filter

Find all configurations matching criteria (not just optimal)

Build docs developers (and LLMs) love