Public API
Run MAIVE, WAIVE, WLS, and RTMA models from your own scripts and pipelines.
The API is free and anonymous: no accounts, no API keys, no sign-up. It is the same compute this web app uses, given a documented JSON contract. Abuse is bounded by server-side concurrency caps and edge rate limits rather than by identity.
Base URL
https://api.maive.euContent type is application/json in both directions. The machine-readable contract is the OpenAPI 3 spec, which is the source of truth; the usage guide has the same examples in narrative form.
Endpoints
| Endpoint | Kind | Description |
|---|---|---|
POST /v1/run-model | Sync | Run MAIVE, WAIVE, or WLS and get the result in the response. |
POST /v1/run-rtma | Sync | Run RTMA and get the result in the response. |
POST /v1/runs | Async | Queue a run; returns a jobId immediately. |
GET /v1/runs/{jobId} | Async | Poll a run; returns the result once it has succeeded. |
GET /v1/health | Meta | Health check. |
Synchronous or asynchronous
Async is the recommended default.
Synchronous endpoints return the result in the same response, which is the simplest thing to call, but they are subject to the edge's roughly 100 second proxy cap. That is comfortable for typical runs (about 15 to 60 seconds including a cold start) and unsuitable for anything larger.
The asynchronous path (POST /v1/runs then poll GET /v1/runs/{jobId} every 2 to 5 seconds) holds no long-lived connection, so it has no failure mode tied to run duration. Use it by default, especially for batch or CI usage. Batch status for several runs at once: GET /v1/runs?ids=a,b,c (up to 100 ids, statuses only).
Data
Send data as an array of row objects. Columns are resolved by canonical key name when present (matched case-insensitively); otherwise the first 3 or 4 keys are read positionally in the order effect, se, n_obs, study_id.
| Field | Type | Required for | Notes |
|---|---|---|---|
effect | number | MAIVE-family, RTMA | Estimated effect size. |
se | number | MAIVE-family, RTMA | Standard error; must be greater than 0. |
n_obs | integer | MAIVE-family | Number of observations; must be a positive integer. |
study_id | string | Optional | Enables study clustering. If present, rows must be at least unique studies plus 3. |
The MAIVE family (/v1/run-model) needs 3 or 4 columns and at least 4 rows. RTMA (/v1/run-rtma) needs 2 columns (effect, se); rows with a missing or non-positive se are silently dropped. These rules mirror the app's own validation page and run server-side, so you get a structured 400 instead of a raw R error.
Parameters
Every parameter is optional; unset ones fall back to the defaults below.
A minimal valid request is just {"data": [...]}:
{
"data": [
{"effect": 0.42, "se": 0.11, "n_obs": 120},
{"effect": 0.31, "se": 0.06, "n_obs": 90},
{"effect": 0.55, "se": 0.20, "n_obs": 45},
{"effect": 0.12, "se": 0.04, "n_obs": 200}
]
}MAIVE, WAIVE, and WLS
| Parameter | Values | Default |
|---|---|---|
modelType | MAIVE | WAIVE | WLS | MAIVE |
maiveMethod | PET | PEESE | PET-PEESE | EK | PET-PEESE |
weight | equal_weights | standard_weights | adjusted_weights | study_weights | equal_weights |
standardErrorTreatment | not_clustered | clustered | clustered_cr2 | bootstrap | clustered_cr2 |
includeStudyDummies | boolean | false |
includeStudyClustering | boolean | false |
computeAndersonRubin | boolean | false |
useLogFirstStage | boolean | false |
winsorize | number (percent, 0 disables) | 0 |
shouldUseInstrumenting | boolean | derived: false for WLS, true otherwise |
RTMA
| Parameter | Values | Default |
|---|---|---|
favorPositive | boolean | true |
alphaSelect | number | 0.05 |
ciLevel | number | 0.95 |
winsorize | number (percent, 0 disables) | 0 |
Plots (funnelPlot, zScorePlot, and their width and height companions) are excluded by default: each is a base64 PNG of roughly 50KB that most callers do not need. Add ?include=plot to any run or poll request to embed them.
Example: synchronous run
curl -s https://api.maive.eu/v1/run-model \
-H 'Content-Type: application/json' \
-d '{
"data": [
{"effect": 0.42, "se": 0.11, "n_obs": 120},
{"effect": 0.31, "se": 0.06, "n_obs": 90},
{"effect": 0.55, "se": 0.20, "n_obs": 45},
{"effect": 0.12, "se": 0.04, "n_obs": 200}
]
}'Example: asynchronous run
Submit, poll until terminal, then read the result.
# 1. Submit
job=$(curl -s https://api.maive.eu/v1/runs \
-H 'Content-Type: application/json' \
-d '{
"modelType": "MAIVE",
"data": [
{"effect": 0.42, "se": 0.11, "n_obs": 120},
{"effect": 0.31, "se": 0.06, "n_obs": 90},
{"effect": 0.55, "se": 0.20, "n_obs": 45},
{"effect": 0.12, "se": 0.04, "n_obs": 200}
]
}' | jq -r '.jobId')
echo "jobId: $job"
# 2. Poll until terminal
while true; do
status=$(curl -s "https://api.maive.eu/v1/runs/$job" | tee /tmp/run.json | jq -r '.status')
echo "status: $status"
[[ "$status" == "succeeded" || "$status" == "failed" || "$status" == "timedout" ]] && break
sleep 3
done
# 3. Read the result
jq '.result' /tmp/run.jsonErrors and rate limits
Every error shares one envelope:
{
"error": {
"code": "validation_error",
"message": "Data must have 3 or 4 columns; found 6."
}
}| Code | Status | Meaning |
|---|---|---|
validation_error | 400 | The request body failed validation. |
not_found | 404 | Unknown or expired jobId. |
method_not_allowed | 405 | The HTTP method is not supported on this route. |
payload_too_large | 413 | The dataset is too large to queue (roughly 200KB of JSON). Use a synchronous endpoint instead. |
rate_limited | 429 | Edge rate limit or the backend concurrency cap was hit. |
internal_error | 500 | An unexpected server-side error occurred. |
not_configured | 503 | This deployment has no async runs infrastructure configured. |
Two guardrails apply: a hard concurrency cap on the compute backend, and per-IP rate limiting at the edge. Both are tuned from observed load, so treat any 429 as "retry with backoff" rather than a hard quota.
jobId and privacy
- A
jobIdis an opaque bearer token, not an account-scoped identifier. Anyone holding it can read that run's status and result, so treat it like a share link. - Runs and their results expire after 48 hours; polling after that returns
404 not_found. - Synchronous runs are stateless. Asynchronous runs persist the parameters and the result for up to 48 hours; the input dataset itself is not persisted beyond the transient queue message.
- Do not submit confidential or personally identifiable data. There is no data-classification or redaction layer; treat every request the way you would treat a request to any other unauthenticated public web service.
Citation
If you use MAIVE in published or reported work, please cite the paper:
How to Cite This App
Please cite the MAIVE paper when using this tool for your research.
Irsova, Z., Bom, P.R.D., Havranek, T., & Rachinger, H. (2025). Spurious precision in meta-analysis of observational research. Nature Communications, 16, 8454. https://doi.org/10.1038/s41467-025-63261-0