The NMMA API is asynchronous. Jobs are submitted and processed in the background. Follow these steps:
Same shape, but POST /nmma/api/compare fits several models (2–16) on the same
event with identical shared parameters and ranks them by Bayesian evidence:
Use GET /nmma/api/jobs/<uid> to list every job (single-fit or compare) a
user has ever submitted, grouped by event — useful for a "previous fits" panel without
re-polling every job individually.
| Code | Meaning |
|---|---|
| 200 | OK — result found in cache or status retrieved |
| 202 | Accepted — job submitted, processing in background |
| 400 | Bad request — missing or invalid parameter |
| 401 | Unauthorized — no uid supplied |
| 403 | Forbidden — uid does not exist |
| 404 | Not found — job ID does not exist |
| 429 | Rate limit exceeded — see Rate limiting below |
| 500 | Internal server error |
Each authenticated user (Astro-COLIBRI UID) is limited to 10 requests per day,
tracked separately for POST /nmma/api/fit and POST /nmma/api/compare
(each has its own 10/day quota). An identical, already-cached fit request does not count against
the quota differently — it still increments the counter, but returns instantly (HTTP 200)
instead of running a fresh fit. A POST /nmma/api/compare call counts as
one request regardless of how many models are compared (2 or 16) — the
quota is charged once per HTTP request, not once per model.
When the limit is exceeded, the API returns HTTP 429 with a reset time.
The lightcurve_url must point to a CSV file with the following columns
(exact names, lower-case):
| Column | Type | Required | Description |
|---|---|---|---|
| mjd | Float | yes | Observation time as Modified Julian Date (e.g. 59775.234) — not an ISO string |
| mag | Float | yes | Observed magnitude — leave blank / NaN for a non-detection |
| mag_err | Float | yes | Photometric uncertainty (mag) |
| filter | String | yes | Filter/band name (e.g. ztfg, ztfr, atlas_o) |
| mag_ul | Float | yes* | Upper-limit magnitude, used when mag is blank/NaN or 99.0 (non-detection). Column must exist even if every row is a real detection — leave it blank/NaN in that case |
| source | String | only for multi-telescope + quality filtering | Telescope/survey name (e.g. ztf, atlas, lsst) — matched against source_filter |
| flag | String | required if source is present | Per-observation quality flag (e.g. good, bad, average) — ZTF/LSST keep "good" only, ATLAS keeps "average" only, others fall back to quality_filter. Upper limits are always kept regardless of flag |
Rows missing mag and with no usable mag_ul
either are dropped as unparseable. A filter/band left with upper limits only (zero real
detections) is also dropped entirely — NMMA needs at least one detection per band.
The timeshift parameter adjusts the reference time of the fit.
Pass it as a scalar or as a prior dict matching the model prior type
(use GET /nmma/api/prior_info/<model> to check):
| Shape | Prior type | Example |
|---|---|---|
| {"min": ..., "max": ...} | uniform / log-uniform | {"min": -30, "max": 1} |
| {"mu": ..., "sigma": ...} | gaussian | {"mu": 0, "sigma": 5} |
| {"peak": ...} | fixed (delta function) | {"peak": -10} |
| float | fixed scalar | -10.0 |
| null | no timeshift | null |
Returns the list of available light-curve models. Curated down to the eleven canonical supernova templates validated in the Astro-COLIBRI NMMA paper (one template per physical subclass), plus five kilonova models for gravitational-wave follow-up and adversarial supernova/kilonova discrimination. Results are cached for 1 hour.
| Field | Type | Description |
|---|---|---|
| models | Object | Dictionary of model key => human-readable "type - template" label |
| count | Int | Number of available models |
Returns the timeshift prior metadata for a given model.
Use this to know which shape to pass in the timeshift field of POST /nmma/api/fit
or POST /nmma/api/compare.
| Parameter | Type | Description |
|---|---|---|
| model | String | Model name (e.g. salt3, Piro2021) — see GET /nmma/api/models |
| Field | Type | Description |
|---|---|---|
| timeshift_type | String | uniform, log-uniform, fixed, gaussian, empty |
| timeshift_min | Float | Minimum bound (uniform / log-uniform) |
| timeshift_max | Float | Maximum bound (uniform / log-uniform) |
| timeshift_peak | Float | Fixed value (delta function) |
| timeshift_mu | Float | Mean (gaussian) |
| timeshift_sigma | Float | Standard deviation (gaussian) |
Submits a single-model light-curve fitting job. The server responds immediately with HTTP 202 and a job ID,
then processes the fit asynchronously. Poll GET /nmma/api/status/<_id>
every ~10 seconds to retrieve results. Identical requests (same parameters, hashed together
into the job ID) return cached results instantly (HTTP 200) instead of re-running the fit.
Rate limit: 10 requests per day per Astro-COLIBRI UID.
| Parameter | Type | Description |
|---|---|---|
| event_name | String | Name of the transient candidate (e.g. SN2022oqm) |
| lightcurve_url | String | URL to the photometry CSV file — see Workflow section for format |
| uid | String | Astro-COLIBRI user ID (authentication and rate limiting) |
| Parameter | Default | Type | Description |
|---|---|---|---|
| model | nugent-sn1a | String | Model name — see GET /nmma/api/models |
| source_filter | ztf | String | Telescope source(s), comma-separated (e.g. ztf,atlas) |
| bands | (all) | String | Optional band filter on top of source_filter, comma-separated (e.g. ztf_g,ztf_r) |
| quality_filter | good | String | Fallback quality flag for sources without a dedicated rule (see CSV format) |
| tmin | 0 | Float | Start of the fit window, days relative to the first observation. This is the server's own fallback when omitted — the Astro-COLIBRI app itself always sends an explicit value computed from the selected telescope(s)' actual data coverage |
| tmax | 7 | Float | End of the fit window, days relative to the first observation. Same caveat as tmin: this is only the server-side fallback for callers that omit it — the Astro-COLIBRI app always computes and sends the real end of the selected telescope(s)' coverage (last detection date minus first detection date), not this fixed 7-day default |
| dt | 0.25 | Float | Time step for the model light-curve grid (days) |
| trigger_time | (first obs.) | Float | MJD to use as the fit's own t=0. Defaults to the earliest observation in the CSV when omitted |
| first_detection | null | String | Display-only: bare MJD or ISO-ish date/time of the true first detection (e.g. TNS discovery date). Re-baselines the plot's x-axis and draws a dotted trigger marker — never affects the fit itself |
| error_budget | 0.25 | Float | Photometric error budget added in quadrature (mag) |
| nlive | 2048 | Int | Live points — higher = more accurate but slower |
| generation_seed | 42 | Int | Random seed for reproducibility |
| sampler | pymultinest | String | pymultinest, dynesty, or ultranest |
| interpolation_type | sklearn_gp | String | sklearn_gp or keras (keras requires a GPU) |
| timeshift | null | Float or Dict | Timeshift prior — see Workflow section for all shapes |
| redshift | null | Float | Known spectroscopic (TNS) redshift. When set, luminosity_distance is fixed to D_L(z) (Planck18) instead of being fitted freely |
| use_ebv | true | Boolean | Enable E(B-V) as a free parameter (sampled between 0 and ebv_max) |
| ebv_max | 0.5724 | Float | Maximum E(B-V) — typically pre-filled from the SFD dust map at the event position by the caller, user-editable |
| extinction_law | G23_MW | String | P92_SMC_host (host-frame SMC, Pei 1992) or G23_MW (Galactic foreground, Gordon 2023, Rv=3.1) |
| em_transient_class | (inferred) | String | supernova, grb, shock, simple_kilonova, svd, ... or a comma-separated combination. Left empty, it is inferred from the model name (recommended) |
| svd_path | null | String | Local path to pre-downloaded SVD surrogate models (kilonova/GRB models only) |
| local_only | false | Boolean | Restrict model-grid generation to locally cached data, skipping any network fetch |
| bestfit | true | Boolean | Save and return best-fit parameters |
| plot_colibri | true | Boolean | Generate the Astro-COLIBRI-styled light-curve and corner plots |
| Field | Type | Description |
|---|---|---|
| _id | String | SHA1 job ID — use to poll GET /nmma/api/status/<_id> |
| status | String | Always "pending" at submission |
Fits 2–16 models on the same event with identical shared parameters (time range,
extinction, redshift, sources, ...), then ranks them by Bayesian evidence (ln Z) and
returns a comparison table plus two overlay plots (light curve + corner). Every requested
model is fitted and ranked, but only the top 3 by ln Z are drawn on the overlay plots to
keep them readable. Same async pattern as POST /nmma/api/fit: submit, poll
GET /nmma/api/status/<_id>.
Rate limit: 10 requests per day per Astro-COLIBRI UID (independent from the /nmma/api/fit quota).
| Parameter | Type | Description |
|---|---|---|
| event_name | String | Name of the transient candidate (e.g. SN2022oqm) |
| lightcurve_url | String | URL to the photometry CSV file — see Workflow section for format |
| uid | String | Astro-COLIBRI user ID (authentication and rate limiting) |
| models | Array<String> | 2–16 distinct model names (duplicates are silently de-duped) — see GET /nmma/api/models |
Every optional field documented for POST /nmma/api/fit above applies here too
(except model, replaced by models) and is shared across every model
in the comparison — Bayes factors are only meaningful when every compared model is fit to
identical data and settings.
| Field | Type | Description |
|---|---|---|
| _id | String | SHA1 job ID — use to poll GET /nmma/api/status/<_id> |
| status | String | Always "pending" at submission |
See the status endpoint below for the shape of the
completed comparison result (the comparison ranking table, chi2_red,
tier, and the two overlay plot URLs).
Polls the status of a job submitted via either POST /nmma/api/fit or
POST /nmma/api/compare. Returns the full result when
status == "completed". Recommended polling interval: every 10 seconds.
The response shape depends on which endpoint the job was submitted to — see the two
tables below.
| Parameter | Type | Description |
|---|---|---|
| job_id | String | SHA1 job ID returned by POST /nmma/api/fit or POST /nmma/api/compare |
This example ID is fictitious — clicking it
will return HTTP 404 "Job not found" unless it happens to match a real job. Use a real _id
from your own POST /nmma/api/fit or POST /nmma/api/compare response to see an actual result.
| Field | Type | When present | Description |
|---|---|---|---|
| _id | String | always | SHA1 job ID |
| status | String | always | pending | running | completed | failed |
| bestfit_params | Object | completed | Full best-fit parameter dump straight from NMMA's own output — includes physical parameters alongside bookkeeping fields (chi2_per_dof, model_error, log_prior, Best fit index, ...) |
| fit_parameters | Array<String> | completed | Names of the bestfit_params keys that are actual physical fit parameters — the same set the corner plot is built from (drops sampler bookkeeping and DeltaFunction-fixed columns). Use this to filter bestfit_params down to what's scientifically meaningful |
| lightcurve | Object | completed | {"url": "..."} — Storage URL for the light-curve PNG |
| corner | Object | completed | {"url": "..."} — Storage URL for the corner-plot PNG |
| nmma_settings | Object | completed | All settings used for the fit (stringified) |
| error | String | failed | Error message describing the failure |
| Field | Type | When present | Description |
|---|---|---|---|
| _id | String | always | SHA1 job ID |
| status | String | always | pending | running | completed | failed |
| type | String | always | Always "compare" — use this to tell a compare job's status response apart from a single-fit one |
| models | Array<String> | completed | Every model that fitted successfully (at least 2 required, others may have been silently dropped) |
| plot_models | Array<String> | completed | Subset of models (top 3 by ln Z) actually drawn on the overlay plots — every model is still ranked in comparison regardless |
| comparison | Array<Object> | completed | One row per fitted model, sorted by ln Z descending — see fields below |
| caption | Object | completed | Plain-language notes explaining the ranking: occam (Bayesian Occam's razor), chi2_caveat, tiers (Jeffreys/Kass & Raftery scale), scope_caveat |
| compare_lightcurve | Object | completed (best-effort) | {"url": "..."} — overlay light-curve PNG for the top 3 models. Absent if plotting failed (non-fatal) |
| compare_corner | Object | completed (best-effort) | {"url": "..."} — overlay corner-plot PNG for the top 3 models. Absent if plotting failed (non-fatal) |
| nmma_settings | Object | completed | Settings shared by every fitted model (stringified) |
| error | String | failed | Error message describing the failure |
| Field | Type | Description |
|---|---|---|
| model | String | Raw NMMA model key (e.g. "salt3") |
| ln_z | Float | Log Bayesian evidence |
| ln_z_err | Float | Estimated numerical error on ln_z from the nested sampler |
| delta_ln_z | Float | ln Z of the best model (reference) minus this row's ln Z — 0 for the reference itself |
| tier | String | Jeffreys/Kass & Raftery (1995) interpretation of |delta_ln_z|: inconclusive (<1), substantial (<2.5), strong (<5), decisive (≥5) |
| chi2_red | Float | null | NMMA's own reduced chi-square (detections only, all bands combined) — a secondary sanity check, not a ranking criterion. null if unavailable for that model |
| is_reference | Boolean | true for the single highest-ln-Z row (the "best fit") |
Lists every job (single-fit or compare) a user has submitted, grouped by event name.
Lightweight by design — each entry only carries its id and last known status, not the
full result. Fetch GET /nmma/api/status/<id> for a specific job's full
payload once you know which one you want. Reads the same Firestore
users/<uid>.job_ids.nmma record the Astro-COLIBRI app itself uses for its
"NMMA Job History" panel, so this endpoint's result matches exactly what you see there.
| Parameter | Type | Description |
|---|---|---|
| uid | String | Astro-COLIBRI user ID |
An object keyed by event name, each value a list of {"id", "status"} objects
for that event's jobs.
"your_firebase_uid" is a placeholder —
clicking it will return an empty {} since no such user exists. Replace it with a
real Astro-COLIBRI uid to see actual job history.