# URL format — roamgap optimizer

> Normative grammar for shareable optimizer URLs. The canonical spec lives in
> the repo at `specs/URL_FORMAT.md`; this page is the stable public URL.

## Paths

| Path | Mode |
| ---- | ---- |
| `/year` | Annual planner — whole year (the only planner mode) |

## Shared parameters

| Name | Type | Notes |
| ---- | ---- | ----- |
| `country` | ISO 3166-1 alpha-2 | Always uppercase. **Required.** |
| `sub` | ISO 3166-2 | Subdivision (e.g. `DE-BY`). Must begin with `country-`. Free-tier. |
| `year` | 1900..2100 | Defaults to the current calendar year. |
| `months` | 1..12 (repeated) | `months=3&months=4` allows March or April. |
| `exclude` | 1..7 (repeated) | ISO weekday — Mon=1, Sun=7. Rejects trips that consume PTO on those days. |
| `block` | YYYY-MM-DD:YYYY-MM-DD (repeated) | Blocked ranges; user unavailable. `start <= end`. |
| `wd` | 1..7 (repeated) | Workweek override; only when overriding the country default. |

## Whole-year planner (`/year`)

| Name | Type | Default |
| ---- | ---- | ------- |
| `pto` | 0..60 | Annual leave budget. Required (or empty state). |
| `max` | 3..30 | Max calendar days per trip. Required (or empty state). |
| `min` | 3..30 | 3 |
| `lt` | 1..8 | Smart default from `pto`. Tunes the "Longest breaks" plan. |
| `mode` | `exhaust` or `selective` | `exhaust` |
| `plans` | 1..10 | 5 |

(A single-break finder was removed from the UI; the `POST /api/trip` JSON endpoint still answers single-break queries — see the OpenAPI below.)

## Examples

```
/year?country=DE&pto=30&max=14&year=2026
/year?country=DE&pto=30&max=14&sub=DE-BY&year=2026
/year?country=KE&pto=25&max=10&year=2026&months=3&months=4&exclude=5
```

## Canonicalisation

Parameter names ascend ASCII-lexically. Country codes uppercased. Multi-value
arrays sort ascending. Parameters equal to their default are dropped from the
canonical form.

## Decoding errors

- Required missing → empty form, no error.
- Required malformed → form with inline error.
- Optional malformed → that parameter is dropped silently, the rest decode.
- Unknown parameters are ignored on decode and preserved on share.

## Source

- Live planner: https://roamgap.ike.work/year
- This page: https://roamgap.ike.work/about/url-format.md
- JSON Schema for the input: https://roamgap.ike.work/api/schemas/AnnualOptimizeInput.json
- OpenAPI: https://roamgap.ike.work/api/openapi.yaml
