Base URL & how it fits together.
All requests go to the versioned base path. The engine itself is a GPU-native, proprietary factor-structured optimization core — the API surface is intentionally simple: submit a job, poll it, fetch the result.
https://asymmetrycomputing.com/api/prismThe typical flow is: PUT a dataset (optional, for your own data) → POST /v1/jobs → poll GET /v1/jobs/{id} until status is completed → fetch GET /v1/jobs/{id}/result and, if needed, GET /v1/jobs/{id}/weights.
An API key on every request.
Pass your key in the X-API-Key header. /v1/health, /v1/capabilities, and /v1/access-requests do not require a key — everything else does.
X-API-Key: YOUR_API_KEYDon't have a key yet? Request a free trial key on the API product page — keys are manually approved and emailed, typically within 24–48 hours.
Every endpoint.
GET /v1/health
Liveness check. No API key required.
curl https://asymmetrycomputing.com/api/prism/v1/healthGET /v1/capabilities
Returns supported task types and their current limits. No API key required — use it to introspect what your key tier (or an unauthenticated caller) can do before submitting a job.
curl https://asymmetrycomputing.com/api/prism/v1/capabilitiesPOST /v1/access-requests
Request a trial key. No API key required. Trial keys are manually approved and emailed — this endpoint just files the request and returns a tracking ID.
{
"name": "Jane Doe",
"email": "jane@fund.example",
"company": "Example Capital",
"use_case": "Testing book_rebalance on a 10k-account taxable book"
}{
"request_id": "req_8f2a1c90",
"status": "pending_review"
}PUT /v1/datasets/{name}
Upload a dataset as the raw request body — a .npz archive matching the schema for the task you intend to run (see book_rebalance or portfolio below). Trial keys are capped at 200MB per dataset.
curl -X PUT https://asymmetrycomputing.com/api/prism/v1/datasets/my_book \
-H "X-API-Key: $KEY" \
-H "Content-Type: application/octet-stream" \
--data-binary @my_book.npzGET /v1/datasets
List datasets uploaded under your key.
curl https://asymmetrycomputing.com/api/prism/v1/datasets \
-H "X-API-Key: $KEY"GET /v1/jobs/{id}
Poll job status: queued, running, completed, or failed.
{ "job_id": "job_a91fe0", "status": "running" }GET /v1/jobs/{id}/result
Fetch the full result once the job is completed: solve timings, a summary of the book (turnover, positions, per-segment breakdown), an optional independent-validation block, and the audit chain with its final hash.
{
"job_id": "job_a91fe0",
"status": "completed",
"timings": {
"solve_wall_s": 47.2,
"us_per_account": 94.4
},
"summary": {
"n_accounts": 500000,
"n_names": 1000,
"turnover": 0.083,
"positions": 481932,
"segments": [
{ "profile": "taxable", "accounts": 320000, "turnover": 0.091 },
{ "profile": "tax_deferred", "accounts": 180000, "turnover": 0.068 }
]
},
"validation": {
"reference": "open-source interior-point (CLARABEL), 1e-9 tolerance",
"sample_size": 50,
"max_weight_error_pct": 0.00025,
"gate_pct": 0.05,
"passed": true,
"reference_ms_per_account": 65.0
},
"audit": {
"stages": 6,
"final_hash": "3f1a9c2e7b4d0851f6a2c9de4b7108c3e5f9a1d2b6c847e0f193a5d7c2b8e410"
}
}GET /v1/jobs/{id}/weights
Download the optimized weights as a .npz archive — one row per account, one column per name, aligned to the input dataset's ordering.
curl https://asymmetrycomputing.com/api/prism/v1/jobs/job_a91fe0/weights \
-H "X-API-Key: $KEY" -o weights.npzPOST /v1/jobs
Every job is asynchronous: submit, get a job_id back immediately, then poll. There are two task types today — book_rebalance for multi-account books and portfolio for single-portfolio optimization.
{ "job_id": "job_a91fe0", "status": "queued" }Rebalance a whole book of accounts.
The core, book-scale task. Use it to rebalance thousands to hundreds of thousands of accounts against a target model in one call.
{
"task": "book_rebalance",
"source": "demo | stress_demo | dataset",
"n_accounts": 25000,
"n_names": 1000,
"dataset_id": "my_book",
"precision": "fast | high",
"chunk_size": 5000,
"include_warm_lane": true,
"validate_sample": 50,
"position_max": 0.08
}| Field | Type | Notes |
|---|---|---|
| source | string | demo, stress_demo, or dataset — see below |
| n_accounts | int | required for demo / stress_demo |
| n_names | int | ≤ 1,000 |
| dataset_id | string | required when source is dataset |
| precision | string | fast or high |
| chunk_size | int | accounts processed per internal batch |
| include_warm_lane | bool | include a warm-started fast lane in the run |
| validate_sample | int | accounts to independently validate in-job against the reference solver |
| position_max | float | per-name position cap, as a weight fraction |
Source: demo
Real historical price history, with synthesized accounts and holdings layered on top. Fast way to smoke-test the endpoint and see result shape.
Source: stress_demo
Full-difficulty, realistic book: multi-lot HIFO cost basis built from real price history, sparse model holdings, concentrated legacy positions, a taxable/tax-deferred account mix, wash-sale blocks, and heterogeneous per-account position caps. This is the honest stress test — the 47-second, 500,000-account headline number was measured on this mode.
Source: dataset — .npz schema
Upload your own book via PUT /v1/datasets/{name}, then reference it by dataset_id.
| Key | Shape | Required | Notes |
|---|---|---|---|
| prices | (T, n) | yes | price history, T periods × n names |
| W_cur | (m, n) | no | current weights, m accounts × n names |
| gain_frac | (m, n) | no | unrealized gain as a fraction of position value |
| is_short_term | (m, n) bool | no | short-term vs. long-term lot flag |
| wash_blocked | (m, n) bool | no | positions currently wash-sale blocked |
| profile | (m,) int | no | account profile: 0, 1, or 2 (e.g. taxable / deferred / mixed) |
| w_index | (n,) | no | target model / index weights |
Optimize a single portfolio.
For single-portfolio (not book-scale) optimization — a standard allocation problem over an asset universe.
{
"task": "portfolio",
"source": "demo | dataset",
"n_assets": 5000,
"dataset_id": "my_universe"
}| Key | Shape | Required | Notes |
|---|---|---|---|
| returns | (T, n) | one of returns / B+D | historical returns, T periods × n assets |
| B | (n, k) | one of returns / B+D | factor loadings, paired with D |
| D | (n,) | paired with B | idiosyncratic variances |
| mu | (n,) | no | expected returns |
| w_current | (n,) | no | current portfolio weights |
Trial-tier limits.
| Limit | Value |
|---|---|
| Accounts per job | 25,000 |
| Assets per job | 20,000 |
| Jobs per day | 10 |
| Total jobs (trial key lifetime) | 40 |
| Dataset upload size | 200 MB |
Need more? A production key removes these caps — talk to us about pricing.
Error semantics
| Status | Meaning |
|---|---|
| 401 | Invalid or missing API key |
| 403 | Request exceeds your key's limits (accounts, assets, or dataset size) |
| 429 | Quota reached (jobs/day or lifetime job cap) |
| 500 | Generic failure — response detail reads "Optimization interrupted on host." |