# Darkroom API
> Analog darkroom and film maths as an API, computed locally and deterministically — the three corrections that bite when you develop film and make prints by hand. The reciprocity endpoint corrects long exposures for reciprocity failure, where film loses sensitivity past about a second: corrected time = metered^p (Schwarzschild p ≈ 1.3 for many films, settable per datasheet), so a metered 10-second exposure really wants about 20 seconds, a full stop more, while anything under the threshold is left untouched. The printexposure endpoint adjusts enlarger exposure when you change print size — light spreads as you raise the head, so exposure is proportional to (magnification + 1)², where magnification is print size ÷ negative size: going from 2× to 4× magnification turns a 10-second exposure into 27.8 seconds, about 1.5 stops, ready for f-stop printing. The pushpull endpoint scales development time for pushing or pulling film by N stops — time = base × factor^stops, roughly +40 % per stop pushed — turning a 7-minute base into 13.7 minutes at +2 stops, or 5 minutes pulled a stop. Everything is computed locally and deterministically, so it is instant and private. Ideal for film-photography and darkroom apps, light-meter and timer companions, lab and workshop tools, and analog-photography sites. Pure local computation — no key, no third-party service, instant. Live, nothing stored. 3 compute endpoints. For digital depth-of-field use a photography API; for lab molarity use a dilution API.

## Authentication
All requests require your oanor API key in the `x-oanor-key` header. Get one at https://www.oanor.com/developer/keys.

```bash
curl -H "x-oanor-key: oanor_live_…" "https://api.oanor.com/darkroom-api/..."
```

## Pricing
- **Free** (Free) — 400 calls/Mo, 2 req/s
- **Starter** ($5/Mo) — 11,000 calls/Mo, 6 req/s
- **Pro** ($16/Mo) — 72,000 calls/Mo, 15 req/s
- **Mega** ($49/Mo) — 240,000 calls/Mo, 36 req/s

## Endpoints

### Darkroom

#### `GET /v1/printexposure` — Enlarger exposure by magnification

**Parameters:**
- `old_time_seconds` (query, required, string) — Current print exposure in seconds Example: `10`
- `old_magnification` (query, required, string) — Current magnification (print ÷ negative) Example: `2`
- `new_magnification` (query, required, string) — New magnification Example: `4`

**Example:**
```bash
curl -H "x-oanor-key: $KEY" \
  "https://api.oanor.com/darkroom-api/v1/printexposure?old_time_seconds=10&old_magnification=2&new_magnification=4"
```

**Response:**
```json
{
    "data": {
        "note": "When you raise the enlarger head for a bigger print the light spreads out, so exposure ∝ (magnification + 1)² (magnification = print size ÷ negative size). Adjust by the stops shown using your timer's f-stop mode, then fine-tune with a test strip — paper and focus drift matter too.",
        "inputs": {
            "old_time_seconds": 10,
            "new_magnification": 4,
            "old_magnification": 2
        },
        "stops_change": 1.47,
        "exposure_ratio": 2.778,
        "new_time_seconds": 27.78
    },
    "meta": {
        "timestamp": "2026-06-06T15:30:47.099Z",
        "request_id": "981d4382-06a1-4593-8884-73e54153ee3f"
    },
    "status": "ok",
    "message": "Enlarger exposure",
    "success": true
}
```

#### `GET /v1/pushpull` — Push/pull development time

**Parameters:**
- `base_time_minutes` (query, required, string) — Box-speed development time in minutes Example: `7`
- `stops` (query, required, string) — Stops to push (+) or pull (−) Example: `2`
- `factor_per_stop` (query, optional, string) — Time factor per stop (default 1.4) Example: `1.4`

**Example:**
```bash
curl -H "x-oanor-key: $KEY" \
  "https://api.oanor.com/darkroom-api/v1/pushpull?base_time_minutes=7&stops=2&factor_per_stop=1.4"
```

**Response:**
```json
{
    "data": {
        "note": "Pushing (rating film faster, then over-developing) or pulling scales development time by factor^stops — roughly +40 % per stop pushed is a common starting point, but it is film- and developer-specific, so trust the manufacturer's times where given. Pushing adds contrast and grain; pulling tames them.",
        "inputs": {
            "stops": 2,
            "factor_per_stop": 1.4,
            "base_time_minutes": 7
        },
        "direction": "push",
        "developed_time_minutes": 13.72
    },
    "meta": {
        "timestamp": "2026-06-06T15:30:47.185Z",
        "request_id": "b92817a1-ce16-4606-8dc4-64099c4211ce"
    },
    "status": "ok",
    "message": "Push/pull development",
    "success": true
}
```

#### `GET /v1/reciprocity` — Reciprocity-failure correction

**Parameters:**
- `metered_seconds` (query, required, string) — Metered exposure time in seconds Example: `10`
- `schwarzschild_p` (query, optional, string) — Schwarzschild exponent (default 1.3) Example: `1.3`
- `threshold_seconds` (query, optional, string) — Threshold below which no correction (default 1) Example: `1`

**Example:**
```bash
curl -H "x-oanor-key: $KEY" \
  "https://api.oanor.com/darkroom-api/v1/reciprocity?metered_seconds=10&schwarzschild_p=1.3&threshold_seconds=1"
```

**Response:**
```json
{
    "data": {
        "note": "Reciprocity failure: above ~1 s most films lose sensitivity, so corrected time = metered^p (Schwarzschild p ≈ 1.3 for many films, but it is film-specific — check the datasheet). Below the threshold no correction is applied. Bellows/filter factors are separate and multiply on top.",
        "inputs": {
            "metered_seconds": 10,
            "schwarzschild_p": 1.3,
            "threshold_seconds": 1
        },
        "extra_stops": 1,
        "extra_seconds": 9.95,
        "corrected_seconds": 19.95
    },
    "meta": {
        "timestamp": "2026-06-06T15:30:47.276Z",
        "request_id": "b4c62720-c2f9-46d9-b758-789f700d55ee"
    },
    "status": "ok",
    "message": "Reciprocity correction",
    "success": true
}
```

### Meta

#### `GET /v1/meta` — Spec

**Example:**
```bash
curl -H "x-oanor-key: $KEY" \
  "https://api.oanor.com/darkroom-api/v1/meta"
```

**Response:**
```json
{
    "data": {
        "notes": "Reciprocity t^p (p≈1.3, film-specific); enlarging exposure ∝ (mag+1)²; push/pull time × factor^stops (≈+40 %/stop). Estimates — always confirm with a test strip and the film/developer datasheet. For digital depth-of-field use a photography API; for lab molarity use a dilution API.",
        "service": "darkroom-api",
        "endpoints": {
            "GET /v1/meta": "This document.",
            "GET /v1/pushpull": "Development time scaled for pushing or pulling film by N stops.",
            "GET /v1/reciprocity": "Corrected exposure time for long film exposures (Schwarzschild).",
            "GET /v1/printexposure": "Enlarger exposure change when magnification changes (inverse-square)."
        },
        "description": "Analog darkroom maths: reciprocity-failure correction, enlarger print-exposure adjustment by magnification, and push/pull development scaling."
    },
    "meta": {
        "timestamp": "2026-06-06T15:30:47.349Z",
        "request_id": "bdedf3b7-9946-4ace-b312-42d7a73063b8"
    },
    "status": "ok",
    "message": "Meta",
    "success": true
}
```


---
Marketplace page: https://www.oanor.com/api/darkroom-api
OpenAPI spec: https://www.oanor.com/api/darkroom-api/openapi.json
