REST API
For direct HTTP access without the Python client. All endpoints are under https://campfire.hollisakins.com/api/v1/.
Authentication#
All requests require an Authorization header:
# Using API key
curl -H "Authorization: Bearer sk_your_api_key" \
https://campfire.hollisakins.com/api/v1/objects
# Using JWT access token (from device flow)
curl -H "Authorization: Bearer eyJ..." \
https://campfire.hollisakins.com/api/v1/objects
Data Endpoints#
GET /objects#
Query objects (cross-program grouped sky positions) with filters.
Query Parameters:
| Parameter | Type | Description |
|---|---|---|
programs | string | Comma-separated program slugs |
fields | string | Comma-separated field names |
gratings | string | Comma-separated grating types |
observations | string | Comma-separated observation names |
redshift_min | float | Minimum redshift |
redshift_max | float | Maximum redshift |
redshift_quality | string | Comma-separated quality codes |
max_snr_min | float | Minimum max SNR |
max_snr_max | float | Maximum max SNR |
lists | string | Comma-separated tag slugs (e.g., lrd,blagn) |
inspected_only | boolean | Filter to inspected objects |
has_photometry | boolean | Filter to objects with photometry |
search | string | Text search on object_id / member target_ids |
ra | float | RA for cone search (degrees) |
dec | float | Dec for cone search (degrees) |
radius | float | Search radius (arcsec) |
limit | int | Max results (default: 1000) |
offset | int | Pagination offset |
sort | string | Sort column (object_id, ra, dec, redshift, redshift_quality, field, n_targets, n_spectra, max_snr, max_exposure_time, distance) |
sort_dir | string | 'asc' or 'desc' |
Response:
{
"data": [
{
"object_id": "CAMPFIRE-J095850.12+021234.5",
"ra": 34.1234,
"dec": -5.4567,
"redshift": 2.345,
"redshift_quality": 3,
"field": "COSMOS",
"member_targets": [
{"target_id": "ember_cosmos_p1_12345", "program_slug": "ember-cosmos", "observation": "ember_cosmos_p1", "redshift_auto": 2.345}
]
}
],
"pagination": {"total": 1500, "limit": 1000, "offset": 0}
}
GET /spectra/list#
Flat list of spectra (one row per spectrum) with filters.
Same vocabulary as /objects plus per-spectrum filters (dq_flags_include_any,
dq_flags_include_all, dq_flags_exclude). Each row carries
spectrum_id, target_id, object_id, grating, fits_path,
signal_to_noise, exposure_time, redshift_auto, dq_flags.
GET /spectra#
Get a signed URL for downloading a FITS file.
| Parameter | Type | Description |
|---|---|---|
path | string | FITS file path (required) |
Response: {"url": "https://..."}
GET /spectrum#
Get spectrum JSON data for plotting.
| Parameter | Type | Description |
|---|---|---|
spectrum_id | string | Stable per-spectrum identifier |
Response:
{
"wave": [1.0, 1.1, ...],
"fnu": [0.5, 0.6, ...],
"fnu_err": [0.1, 0.1, ...],
"snr_2d": [[...], [...]],
"n_spatial": 10,
"n_wave": 500,
"profile": [...],
"profile_fit": [...],
"profile_pix": [...]
}
GET /redshift-fit#
Get redshift fitting results.
| Parameter | Type | Description |
|---|---|---|
target_id | string | Target ID |
grating | string | Grating type |
Response:
{
"redshift": 2.345,
"chi2_min": 1.23,
"confidence": 95.5,
"z_grid": [0.0, 0.1, ...],
"chi2_grid": [100, 95, ...],
"model_wave": [...],
"model_fnu": [...]
}
GET /metadata#
Get available filter options.
Response:
{
"programs": [
{"slug": "ember-uds", "program_name": "EMBER-UDS", "pi_name": "...", "is_public": false}
],
"fields": ["COSMOS", "UDS"],
"gratings": ["PRISM", "G395M"],
"observations": ["ember_uds_p4"]
}
GET /observations#
List observations with stats.
Response:
{
"observations": [
{
"observation": "ember_uds_p4",
"program_name": "EMBER-UDS",
"field": "UDS",
"target_count": 450,
"spectrum_count": 1350,
"total_size_bytes": 2147483648
}
]
}
Auth Endpoints#
GET /auth/whoami#
Get current user info. Response: {"user_id": "uuid", "email": "...", "full_name": "..."}
POST /auth/device#
Initiate device flow authorization (for CLI).
Response:
{
"device_code": "...",
"user_code": "WDJB-MJPQ",
"verification_uri": "https://campfire.hollisakins.com/cli-auth",
"verification_uri_complete": "https://campfire.hollisakins.com/cli-auth?code=WDJB-MJPQ",
"expires_in": 900,
"interval": 5
}
POST /auth/device/token#
Poll for tokens after user authorization.
Request: {"grant_type": "urn:ietf:params:oauth:grant-type:device_code", "device_code": "..."}
Response (success): {"access_token": "...", "token_type": "Bearer", "expires_in": 3600, "refresh_token": "..."}
Response (pending): {"error": "authorization_pending"}
POST /auth/refresh#
Refresh an access token.
Request: {"grant_type": "refresh_token", "refresh_token": "..."}
Response: {"access_token": "...", "token_type": "Bearer", "expires_in": 3600, "refresh_token": "..."}
Error Codes#
| Code | Description |
|---|---|
| 200 | Success |
| 400 | Invalid parameters |
| 401 | Invalid/missing authentication |
| 403 | No access to resource |
| 404 | Not found |
| 429 | Rate limited |
| 500 | Server error |
Rate Limits#
- Standard: 100 requests/minute
- Burst: Up to 10 concurrent requests