Skip to main content
POST
/
api
/
v1
/
pricing
/
analysis
Validation & Analysis Jobs
curl --request POST \
  --url https://api.example.com/api/v1/pricing/analysis \
  --header 'Content-Type: application/json' \
  --data '
{
  "operation": "<string>",
  "solver": "<string>",
  "filters": "<string>",
  "objective": "<string>"
}
'
{
  "jobId": "<string>",
  "status": "<string>",
  "submittedAt": "<string>",
  "startedAt": "<string>",
  "completedAt": "<string>",
  "result": {},
  "failedAt": "<string>",
  "error": {
    "error.message": "<string>",
    "error.details": "<string>"
  }
}
The Analysis Jobs API provides asynchronous operations for validating and analyzing pricing configurations. Unlike the synchronous summary endpoint, these operations may take longer to complete as they involve constraint satisfaction programming (CSP) solvers.

Create Analysis Job

POST /api/v1/pricing/analysis
Creates and launches a new asynchronous analysis job. The job is processed in the background, and you can poll for results using the returned job ID.

Request

Headers

Content-Type: multipart/form-data

Parameters

pricingFile
file
required
The YAML file containing the pricing configuration to analyze.
operation
string
required
The type of analysis operation to perform.Options:
  • validate - Verify pricing model coherence
  • optimal - Find optimal configurations (requires filters)
  • subscriptions - Enumerate all valid configurations
  • filter - Find configurations matching criteria (requires filters)
solver
string
required
The constraint satisfaction solver to use.Options:
  • minizinc - MiniZinc solver (recommended)
  • choco - Choco solver (supports validate and subscriptions only)
filters
string
JSON string containing filter criteria. Required for optimal and filter operations.Structure:
{
  "minPrice": 0,
  "maxPrice": 100,
  "maxSubscriptionSize": 5,
  "features": ["gitIntegration", "prioritySupport"],
  "usageLimits": [
    {"name": "maxCollaboratorsPerProject", "value": 10}
  ]
}
objective
string
Optimization objective for optimal operations.Options:
  • minimize - Find lowest-cost configuration
  • maximize - Find highest-cost configuration

Example Requests

curl -X POST "http://localhost:3000/api/v1/pricing/analysis" \
  -F "[email protected]" \
  -F "operation=validate" \
  -F "solver=minizinc"

Response (202 Accepted)

jobId
string
required
Unique identifier for the created job. Use this to check status and retrieve results.
status
string
required
Initial status of the job. Always PENDING when first created.
submittedAt
string
required
ISO 8601 timestamp of when the job was submitted.
Example Response
{
  "jobId": "job-a3f2b91c-4d8e-4b2a-9c1d-5e6f7a8b9c0d",
  "status": "PENDING",
  "submittedAt": "2026-03-05T14:23:45.123Z"
}

Get Job Status

GET /api/v1/pricing/analysis/{jobId}
Retrieve the current status and results (if completed) of an analysis job.

Request

jobId
string
required
The unique identifier returned when the job was created.

Example Request

curl "http://localhost:3000/api/v1/pricing/analysis/job-a3f2b91c-4d8e-4b2a-9c1d-5e6f7a8b9c0d"

Response

The response structure varies based on the job’s current status:

PENDING Status

{
  "jobId": "job-789",
  "status": "PENDING",
  "submittedAt": "2026-03-05T11:00:00Z"
}

RUNNING Status

{
  "jobId": "job-789",
  "status": "RUNNING",
  "submittedAt": "2026-03-05T11:00:00Z",
  "startedAt": "2026-03-05T11:00:05Z"
}

COMPLETED Status

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 job processing started
completedAt
string
required
ISO 8601 timestamp of when job completed
result
object
required
The analysis result. Structure depends on the operation type:For validate operation:
{
  "valid": true
}
For optimal operation:
{
  "optimal": {
    "subscriptions": [
      {
        "plan": "FREE",
        "addOns": [],
        "features": ["latexEditor", "realTimeCollaboration"],
        "usageLimits": [{"name": "maxCollaboratorsPerProject", "value": 1}],
        "cost": "0 USD"
      }
    ],
    "cost": 0
  }
}
See Optimization and Subscriptions for detailed result schemas.

FAILED Status

jobId
string
required
Job identifier
status
string
required
Job status: FAILED
submittedAt
string
required
ISO 8601 timestamp of job submission
startedAt
string
ISO 8601 timestamp of when job started (may be null if failed before starting)
failedAt
string
required
ISO 8601 timestamp of when job failed
error
object
required
Error information
error.message
string
required
Human-readable error message
error.details
string
Technical details or stack trace (optional)
Example Failed Response
{
  "jobId": "job-xyz",
  "status": "FAILED",
  "submittedAt": "2026-03-05T12:00:00Z",
  "startedAt": "2026-03-05T12:00:05Z",
  "failedAt": "2026-03-05T12:00:06Z",
  "error": {
    "message": "Solver timeout after 30s",
    "details": "MiniZinc solver exceeded maximum execution time"
  }
}

Validation Operation

The validate operation verifies the mathematical and logical coherence of a pricing specification.

What Gets Validated

Ensures that plan prices are logically ordered and add-on prices are reasonable relative to plan prices.
Verifies that feature definitions are consistent across plans and that feature hierarchies make sense.
Validates that add-ons are only available for the plans they’re supposed to be available for.
Detects configurations that cannot exist due to constraint conflicts.

Example Validation Request

curl -X POST "http://localhost:3000/api/v1/pricing/analysis" \
  -F "[email protected]" \
  -F "operation=validate" \
  -F "solver=minizinc"
Response:
{
  "jobId": "job-validate-123",
  "status": "PENDING",
  "submittedAt": "2026-03-05T14:30:00Z"
}
After polling:
{
  "jobId": "job-validate-123",
  "status": "COMPLETED",
  "submittedAt": "2026-03-05T14:30:00Z",
  "startedAt": "2026-03-05T14:30:02Z",
  "completedAt": "2026-03-05T14:30:05Z",
  "result": {
    "valid": true
  }
}

Invalid Pricing Model Example

If validation fails:
{
  "jobId": "job-validate-456",
  "status": "COMPLETED",
  "submittedAt": "2026-03-05T14:35:00Z",
  "startedAt": "2026-03-05T14:35:02Z",
  "completedAt": "2026-03-05T14:35:04Z",
  "result": {
    "valid": false,
    "error": "No valid configurations exist: Add-on 'PREMIUM_SUPPORT' requires plan 'ENTERPRISE' which does not exist"
  }
}

Polling Strategy

Since analysis jobs are asynchronous, you need to poll for results:
async function waitForJob(jobId, maxWaitMs = 60000) {
  const startTime = Date.now();
  
  while (Date.now() - startTime < maxWaitMs) {
    const response = await fetch(
      `http://localhost:3000/api/v1/pricing/analysis/${jobId}`
    );
    const job = await response.json();
    
    if (job.status === 'COMPLETED') {
      return job.result;
    }
    
    if (job.status === 'FAILED') {
      throw new Error(job.error.message);
    }
    
    // Wait 2 seconds before next poll
    await new Promise(resolve => setTimeout(resolve, 2000));
  }
  
  throw new Error('Job timeout');
}

// Usage
const result = await waitForJob('job-123');
console.log('Analysis complete:', result);
Use exponential backoff for polling in production: start with 1s intervals and increase to 5s for long-running jobs.

Error Responses

400 Bad Request

{
  "error": "Missing required fields: operation and solver are required"
}
{
  "error": "Invalid filters format. Must be valid JSON."
}

404 Not Found

{
  "error": "Job not found"
}

500 Internal Server Error

{
  "error": "Internal server error during job submission",
  "details": "Failed to initialize MiniZinc solver"
}

Implementation

The analysis job endpoints are implemented in /home/daytona/workspace/source/analysis_api/src/api/analysis.ts:23 and :138. Jobs are stored in-memory by default. For production use, implement persistent storage (Redis, database) to survive server restarts.

Optimization

Find optimal configurations with custom criteria

Subscriptions

Enumerate all valid subscription configurations

Build docs developers (and LLMs) love