# API Almanac API reference

Small, deterministic lookups and calculations — time zones, holidays, sunrise, units, country and currency facts, validators — behind one key. Every response is JSON. Static lookups are cacheable for a day; anything that depends on *now* is not cached.

Rate limits and plan ceilings are reported on every response in the `X-Gw-*` headers (`X-Gw-Remaining`, `X-Gw-Reset`), so clients and agents can pace themselves.

Base URL: `https://api.apialmanac.com/`. Send your key in the `X-API-Key` header; the remaining allowance comes back on every response in `X-Gw-Remaining`.

MCP server: `https://mcp.apialmanac.com/` (bearer token = the same key).

## Errors every operation can return

- `400` A parameter is missing, malformed or out of range

```json
{
  "error": "string",
  "message": "string",
  "param": "string"
}
```

- `401` Missing or invalid API key (from the gateway)
- `429` Plan ceiling or rate limit reached; see X-Gw-Reset (from the gateway)

# Time

# Time

## GET /v1/time/now

**The current time in a time zone, with offset, DST flag and ISO week**

Pass `at` to describe a specific instant instead of now — handy for tests and for "what time is it in Tokyo when it's 9am in New York" when combined with `/v1/time/convert`.

### Parameters

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `tz` | query | string | no | IANA zone, e.g. America/New_York Example: Europe/Paris |
| `at` | query | string | no | ISO-8601 instant to describe instead of now Example: 2026-07-01T12:00:00Z |

### Responses

- `200` OK

```json
{
  "zone": "Europe/Paris",
  "iso": "2026-07-01T14:00:00+02:00",
  "date": "2026-07-01",
  "time": "14:00:00",
  "weekday": "Wednesday",
  "utc": "2026-07-01T12:00:00Z",
  "unix": 1782907200,
  "offset": "+02:00",
  "offset_minutes": 120,
  "abbreviation": "GMT+2",
  "dst": true,
  "dst_observed": true,
  "iso_week": 27,
  "iso_week_year": 2026,
  "day_of_year": 182
}
```

### Example

```bash
curl "https://api.apialmanac.com/v1/time/now" \
  -H "X-API-Key: YOUR_KEY"
```

## GET /v1/time/convert

**Convert a time from one zone to another**

`at` is a wall-clock time in `from` (e.g. `2026-03-08T02:30`) or an explicit instant with Z or offset. Wall times that fall in a DST gap are moved forward like most calendar apps do.

### Parameters

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `at` | query | string | yes | Wall time in `from`, or an ISO-8601 instant Example: 2026-10-08T09:00 |
| `to` | query | string | yes | Zone to convert to Example: Asia/Tokyo |
| `from` | query | string | no | Zone `at` is expressed in Example: America/New_York |

### Responses

- `200` OK

```json
{
  "input": "2026-10-08T09:00",
  "from": {
    "zone": "America/New_York",
    "iso": "2026-10-08T09:00:00-04:00",
    "offset": "-04:00"
  },
  "to": {
    "zone": "Asia/Tokyo",
    "iso": "2026-10-08T22:00:00+09:00",
    "offset": "+09:00"
  },
  "utc": "2026-10-08T13:00:00Z",
  "unix": 1791464400,
  "difference_minutes": 780,
  "difference": "+13:00"
}
```

### Example

```bash
curl "https://api.apialmanac.com/v1/time/convert?at=2026-10-08T09%3A00&to=Asia%2FTokyo" \
  -H "X-API-Key: YOUR_KEY"
```

## GET /v1/time/zones

**Every IANA time zone with its current UTC offset and abbreviation**

### Parameters

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `q` | query | string | no | Filter: substring of the zone name, case-insensitive Example: america/ |
| `at` | query | string | no | Instant to evaluate offsets at (default now) Example: string |

### Responses

- `200` OK

```json
{
  "at": "2026-10-08T13:00:00Z",
  "count": 2,
  "zones": [
    {
      "zone": "America/New_York",
      "offset": "-04:00",
      "offset_minutes": -240,
      "abbreviation": "EDT"
    },
    {
      "zone": "America/Sao_Paulo",
      "offset": "-03:00",
      "offset_minutes": -180,
      "abbreviation": "GMT-3"
    }
  ]
}
```

### Example

```bash
curl "https://api.apialmanac.com/v1/time/zones" \
  -H "X-API-Key: YOUR_KEY"
```

# Countries

## GET /v1/countries/{code}/timezones

**The IANA time zones a country uses, with current offsets**

### Parameters

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `code` | path | string | yes | ISO 3166-1 alpha-2 Example: CA |

### Responses

- `200` OK

```json
{
  "country": "CA",
  "count": 2,
  "timezones": [
    {
      "zone": "America/Toronto",
      "comment": "Eastern - ON & QC (most areas)",
      "offset": "-04:00",
      "abbreviation": "EDT"
    },
    {
      "zone": "America/Vancouver",
      "comment": "Pacific - BC (most areas)",
      "offset": "-07:00",
      "abbreviation": "PDT"
    }
  ]
}
```

### Example

```bash
curl "https://api.apialmanac.com/v1/countries/CA/timezones" \
  -H "X-API-Key: YOUR_KEY"
```

# Dates

# Date

## GET /v1/date/diff

**Days, weeks, months and business days between two dates**

Business days count both ends when they are working days (like Excel's NETWORKDAYS). With `country`, public holidays are excluded too; without it, only the weekend is.

### Parameters

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `from` | query | string | yes | Start date Example: 2026-12-18 |
| `to` | query | string | yes | End date Example: 2027-01-05 |
| `country` | query | string | no | Country for holidays and weekend definition Example: US |
| `subdivision` | query | string | no | State / province for regional holidays Example: string |

### Responses

- `200` OK

```json
{
  "from": "2026-12-18",
  "to": "2027-01-05",
  "days": 18,
  "weeks": 2.57,
  "calendar": {
    "years": 0,
    "months": 0,
    "days": 18
  },
  "business_days": 11,
  "weekend_days": 6,
  "holiday_days": 2,
  "calendar_used": "United States",
  "holidays": [
    {
      "date": "2026-12-25",
      "name": "Christmas Day"
    },
    {
      "date": "2027-01-01",
      "name": "New Year's Day"
    }
  ]
}
```

### Example

```bash
curl "https://api.apialmanac.com/v1/date/diff?from=2026-12-18&to=2027-01-05" \
  -H "X-API-Key: YOUR_KEY"
```

## GET /v1/date/add

**Add calendar or business days to a date**

Negative `days` go backwards. With `business=true` weekends (and holidays, if `country` is given) are skipped.

### Parameters

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `start` | query | string | yes | Start date Example: 2026-12-23 |
| `days` | query | integer | yes | Days to add (negative to subtract) Example: 5 |
| `business` | query | boolean | no | Count business days instead of calendar days Example: False |
| `country` | query | string | no | Country for holidays and weekend definition Example: US |
| `subdivision` | query | string | no | State / province for regional holidays Example: string |

### Responses

- `200` OK

```json
{
  "start": "2026-12-23",
  "days": 5,
  "business": true,
  "result": "2026-12-31",
  "weekday": "Thursday",
  "calendar_days_elapsed": 8,
  "calendar_used": "United States",
  "skipped": [
    {
      "date": "2026-12-25",
      "reason": "Christmas Day"
    },
    {
      "date": "2026-12-26",
      "reason": "weekend"
    },
    {
      "date": "2026-12-27",
      "reason": "weekend"
    }
  ]
}
```

### Example

```bash
curl "https://api.apialmanac.com/v1/date/add?start=2026-12-23&days=5" \
  -H "X-API-Key: YOUR_KEY"
```

## GET /v1/date/parse

**Turn natural language like "next Tuesday at 3pm" or "in 3 weeks" into ISO dates**

Relative phrases are resolved against `ref` (default: now) in `tz`. Several dates in one text come back as separate results. `certain` says which parts were stated explicitly versus assumed.

### Parameters

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `text` | query | string | yes | Text containing one or more dates Example: Let's meet next Tuesday at 3pm for an hour |
| `ref` | query | string | no | Reference instant for relative phrases (ISO-8601, default now) Example: 2026-10-08T12:00:00Z |
| `tz` | query | string | no | Zone the text is spoken in Example: America/New_York |
| `forward` | query | boolean | no | Prefer future dates for ambiguous phrases like "Friday" Example: True |

### Responses

- `200` OK

```json
{
  "text": "Let's meet next Tuesday at 3pm for an hour",
  "ref": "2026-10-08T12:00:00Z",
  "zone": "America/New_York",
  "count": 1,
  "results": [
    {
      "text": "next Tuesday at 3pm",
      "index": 11,
      "start": {
        "iso": "2026-10-13T15:00:00-04:00",
        "utc": "2026-10-13T19:00:00Z",
        "date": "2026-10-13",
        "time": "15:00",
        "certain": {
          "date": true,
          "time": true
        }
      },
      "end": null
    }
  ]
}
```

### Example

```bash
curl "https://api.apialmanac.com/v1/date/parse?text=Let%27s+meet+next+Tuesday+at+3pm+for+an+hour" \
  -H "X-API-Key: YOUR_KEY"
```

## GET /v1/date/calendar

**Convert a date to or from another calendar: Hebrew, Islamic, Persian, Chinese, Japanese eras, Julian and more**

Give `date` to convert a Gregorian date *into* `calendar`; give `year`, `month` and `day` to convert *from* it. `month` accepts a name (`Tishri`, `Ramadan`, `First Month`) or a number, where numbers are the month's position in its year: a Hebrew or Chinese leap year has 13, so `months_in_year` is returned alongside. Names are the safer choice. Japanese years need `era` (meiji, taisho, showa, heisei, reiwa).

### Parameters

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `calendar` | query | enum | yes | Target or source calendar One of: hebrew, islamic-umalqura, islamic-civil, persian, chinese, japanese, buddhist, indian, coptic, ethiopic, roc, julian |
| `date` | query | string | no | Gregorian date to convert (default: today) Example: 2026-10-09 |
| `year` | query | integer | no | Year in `calendar` (reverse conversion) Example: 1 |
| `month` | query | string | no | Month name or number in `calendar` (reverse conversion) Example: string |
| `day` | query | integer | no | Day in `calendar` (reverse conversion) Example: 1 |
| `era` | query | string | no | Japanese era for reverse conversion Example: reiwa |

### Responses

- `200` OK

```json
{
  "gregorian": "2026-10-09",
  "calendar": "hebrew",
  "label": "Hebrew",
  "year": 5787,
  "month": 1,
  "month_name": "Tishri",
  "months_in_year": 12,
  "day": 28,
  "era": "AM",
  "formatted": "28 Tishri 5787 AM",
  "weekday": "Friday"
}
```

### Example

```bash
curl "https://api.apialmanac.com/v1/date/calendar?calendar=hebrew" \
  -H "X-API-Key: YOUR_KEY"
```

## GET /v1/date/easter

**Easter and the moveable feasts for a year, Western or Orthodox**

### Parameters

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `year` | query | integer | no | Year (default: this year) Example: 2026 |
| `tradition` | query | enum | no | Gregorian computus or the Julian one used by Orthodox churches One of: western, orthodox |

### Responses

- `200` OK

```json
{
  "year": 2026,
  "tradition": "western",
  "easter": "2026-04-05",
  "feasts": [
    {
      "name": "Ash Wednesday",
      "date": "2026-02-18",
      "offset_days": -46
    },
    {
      "name": "Good Friday",
      "date": "2026-04-03",
      "offset_days": -2
    },
    {
      "name": "Easter Sunday",
      "date": "2026-04-05",
      "offset_days": 0
    },
    {
      "name": "Pentecost",
      "date": "2026-05-24",
      "offset_days": 49
    }
  ]
}
```

### Example

```bash
curl "https://api.apialmanac.com/v1/date/easter" \
  -H "X-API-Key: YOUR_KEY"
```

# Holidays

## GET /v1/holidays

**Public holidays for a country and year, optionally for one state or region**

National holidays by default. Add `subdivision` (a state, province or region code such as `TX` or `BY`) to include regional ones. Years 2020–2030 for every country the data covers.

### Parameters

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `country` | query | string | yes | ISO 3166-1 alpha-2 code Example: US |
| `year` | query | integer | no | Year (default: the current year) Example: 2026 |
| `subdivision` | query | string | no | State / province / region code Example: TX |

### Responses

- `200` OK

```json
{
  "country": "US",
  "name": "United States",
  "year": 2026,
  "subdivision": null,
  "weekend": [
    "Saturday",
    "Sunday"
  ],
  "count": 2,
  "holidays": [
    {
      "date": "2026-01-01",
      "weekday": "Thursday",
      "name": "New Year's Day",
      "national": true,
      "subdivisions": null
    },
    {
      "date": "2026-01-19",
      "weekday": "Monday",
      "name": "Martin Luther King Jr. Day",
      "national": true,
      "subdivisions": null
    }
  ]
}
```

### Example

```bash
curl "https://api.apialmanac.com/v1/holidays?country=US" \
  -H "X-API-Key: YOUR_KEY"
```

## GET /v1/holidays/countries

**Countries with holiday data, and their subdivisions**

### Responses

- `200` OK

```json
{
  "count": 2,
  "countries": [
    {
      "country": "US",
      "name": "United States",
      "subdivisions": 57,
      "years": "2020–2030"
    },
    {
      "country": "GB",
      "name": "United Kingdom",
      "subdivisions": 4,
      "years": "2020–2030"
    }
  ]
}
```

### Example

```bash
curl "https://api.apialmanac.com/v1/holidays/countries" \
  -H "X-API-Key: YOUR_KEY"
```

# Cron

## GET /v1/cron

**Validate a cron expression, say it in English and list its next runs in a time zone**

### Parameters

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `expression` | query | string | yes | Five-field cron or a macro like @daily Example: 0 9 * * 1-5 |
| `tz` | query | string | no | Zone the schedule runs in Example: America/New_York |
| `from` | query | string | no | Instant to start from (default now) Example: string |
| `count` | query | integer | no | How many upcoming runs Example: 5 |

### Responses

- `200` OK

```json
{
  "expression": "0 9 * * 1-5",
  "normalized": "0 9 * * 1-5",
  "description": "At 09:00 Monday through Friday",
  "zone": "America/New_York",
  "from": "2026-10-09T15:00:00Z",
  "next": [
    {
      "utc": "2026-10-12T13:00:00Z",
      "local": "2026-10-12T09:00:00-04:00",
      "weekday": "Monday"
    },
    {
      "utc": "2026-10-13T13:00:00Z",
      "local": "2026-10-13T09:00:00-04:00",
      "weekday": "Tuesday"
    }
  ]
}
```

### Example

```bash
curl "https://api.apialmanac.com/v1/cron?expression=0+9+%2A+%2A+1-5" \
  -H "X-API-Key: YOUR_KEY"
```

# Astronomy

# Sun

## GET /v1/sun

**Sunrise, sunset, solar noon, twilights and day length for a place and date**

Times are UTC instants; add `tz` to get local wall-clock times as well. Inside the polar circles a day may have no sunrise or sunset — those fields are null and `polar` says which.

### Parameters

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `lat` | query | number | yes | Latitude in decimal degrees Example: 40.7128 |
| `lon` | query | number | yes | Longitude in decimal degrees Example: -74.006 |
| `date` | query | string | no | Civil date, YYYY-MM-DD (default: today, UTC) Example: 2026-06-21 |
| `tz` | query | string | no | IANA zone for local times Example: America/New_York |

### Responses

- `200` OK

```json
{
  "date": "2026-06-21",
  "location": {
    "lat": 40.7128,
    "lon": -74.006
  },
  "zone": "America/New_York",
  "polar": null,
  "sunrise": {
    "utc": "2026-06-21T09:25:00Z",
    "local": "2026-06-21T05:25:00-04:00"
  },
  "sunset": {
    "utc": "2026-06-22T00:31:00Z",
    "local": "2026-06-21T20:31:00-04:00"
  },
  "solar_noon": {
    "utc": "2026-06-21T16:58:00Z",
    "local": "2026-06-21T12:58:00-04:00"
  },
  "day_length": {
    "seconds": 54360,
    "text": "15h 06m"
  },
  "civil_twilight": {
    "dawn": {
      "utc": "2026-06-21T08:52:00Z"
    },
    "dusk": {
      "utc": "2026-06-22T01:04:00Z"
    }
  },
  "nautical_twilight": {
    "dawn": {
      "utc": "2026-06-21T08:10:00Z"
    },
    "dusk": {
      "utc": "2026-06-22T01:46:00Z"
    }
  },
  "astronomical_twilight": {
    "dawn": {
      "utc": "2026-06-21T07:22:00Z"
    },
    "dusk": {
      "utc": "2026-06-22T02:34:00Z"
    }
  },
  "golden_hour": {
    "morning_end": {
      "utc": "2026-06-21T10:03:00Z"
    },
    "evening_start": {
      "utc": "2026-06-21T23:53:00Z"
    }
  },
  "max_elevation_degrees": 72.7
}
```

### Example

```bash
curl "https://api.apialmanac.com/v1/sun?lat=40.7128&lon=-74.006" \
  -H "X-API-Key: YOUR_KEY"
```

# Moon

## GET /v1/moon

**Moon phase, illumination and the next new and full moons**

Add `lat` and `lon` to get moonrise and moonset for that day.

### Parameters

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `date` | query | string | no | Date or ISO-8601 instant (default now) Example: 2026-10-08 |
| `lat` | query | number | no | Latitude, for moonrise and moonset Example: -90 |
| `lon` | query | number | no | Longitude, for moonrise and moonset Example: -180 |
| `tz` | query | string | no | IANA zone for local times Example: string |

### Responses

- `200` OK

```json
{
  "at": "2026-10-08T12:00:00Z",
  "phase": "Waning Crescent",
  "phase_fraction": 0.91,
  "illumination": 0.08,
  "age_days": 26.9,
  "waxing": false,
  "next_new_moon": "2026-10-10T15:50:00Z",
  "next_full_moon": "2026-10-26T04:12:00Z",
  "moonrise": null,
  "moonset": null
}
```

### Example

```bash
curl "https://api.apialmanac.com/v1/moon" \
  -H "X-API-Key: YOUR_KEY"
```

# Units

# Units

## GET /v1/units

**Every unit the converter knows, grouped by category**

### Parameters

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `category` | query | enum | no | Only this category One of: length, mass, temperature, volume, area, speed, time, data, energy, pressure, power |

### Responses

- `200` OK

```json
{
  "categories": [
    {
      "category": "temperature",
      "base": "c",
      "units": [
        {
          "id": "c",
          "label": "degree Celsius",
          "aliases": [
            "°c",
            "celsius",
            "centigrade",
            "degc"
          ]
        },
        {
          "id": "f",
          "label": "degree Fahrenheit",
          "aliases": [
            "°f",
            "fahrenheit",
            "degf"
          ]
        },
        {
          "id": "k",
          "label": "kelvin",
          "aliases": [
            "kelvin",
            "kelvins"
          ]
        }
      ]
    }
  ]
}
```

### Example

```bash
curl "https://api.apialmanac.com/v1/units" \
  -H "X-API-Key: YOUR_KEY"
```

## GET /v1/units/convert

**Convert a value between two units of the same kind**

Units are matched loosely: `km/h`, `kph` and `kilometers per hour` are the same thing.

### Parameters

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `value` | query | number | yes | The quantity to convert Example: 26.2 |
| `from` | query | string | yes | Unit of `value` Example: mi |
| `to` | query | string | yes | Unit to convert into Example: km |

### Responses

- `200` OK

```json
{
  "value": 26.2,
  "from": {
    "id": "mi",
    "label": "mile"
  },
  "to": {
    "id": "km",
    "label": "kilometre"
  },
  "category": "length",
  "result": 42.164813,
  "formatted": "42.164813 km"
}
```

### Example

```bash
curl "https://api.apialmanac.com/v1/units/convert?value=26.2&from=mi&to=km" \
  -H "X-API-Key: YOUR_KEY"
```

# Validation

# Validate

## GET /v1/validate/iban

**Check an IBAN: country, length and mod-97 check digits**

### Parameters

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `iban` | query | string | yes | IBAN, spaces allowed Example: GB82 WEST 1234 5698 7654 32 |

### Responses

- `200` OK

```json
{
  "input": "GB82 WEST 1234 5698 7654 32",
  "iban": "GB82WEST12345698765432",
  "formatted": "GB82 WEST 1234 5698 7654 32",
  "country": "GB",
  "valid": true,
  "reason": null,
  "check_digits": "82",
  "bban": "WEST12345698765432"
}
```

### Example

```bash
curl "https://api.apialmanac.com/v1/validate/iban?iban=GB82+WEST+1234+5698+7654+32" \
  -H "X-API-Key: YOUR_KEY"
```

## GET /v1/validate/email

**Check an email address: syntax, normalised form, disposable and role-based flags, optional MX lookup**

Set `mx=true` to also check that the domain publishes MX records (a live DNS query).

### Parameters

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `email` | query | string | yes | Address to check Example: Jane.Doe+news@gmail.com |
| `mx` | query | boolean | no | Also look up MX records for the domain Example: False |

### Responses

- `200` OK

```json
{
  "input": "Jane.Doe+news@gmail.com",
  "valid": true,
  "reason": null,
  "local": "Jane.Doe+news",
  "domain": "gmail.com",
  "tag": "news",
  "normalized": "janedoe@gmail.com",
  "disposable": false,
  "role_based": false,
  "mx": {
    "found": true,
    "records": [
      {
        "preference": 5,
        "exchange": "gmail-smtp-in.l.google.com"
      }
    ]
  }
}
```

### Example

```bash
curl "https://api.apialmanac.com/v1/validate/email?email=Jane.Doe%2Bnews%40gmail.com" \
  -H "X-API-Key: YOUR_KEY"
```

## GET /v1/validate/phone

**Parse and validate a phone number: E.164, national format, type and region**

### Parameters

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `number` | query | string | yes | Number in any common format Example: (415) 555-2671 |
| `country` | query | string | no | Default region when the number has no + prefix Example: US |

### Responses

- `200` OK

```json
{
  "input": "(415) 555-2671",
  "valid": true,
  "possible": true,
  "e164": "+14155552671",
  "international": "+1 415 555 2671",
  "national": "(415) 555-2671",
  "rfc3966": "tel:+14155552671",
  "country": "US",
  "country_calling_code": "1",
  "national_number": "4155552671",
  "type": "FIXED_LINE_OR_MOBILE"
}
```

### Example

```bash
curl "https://api.apialmanac.com/v1/validate/phone?number=%28415%29+555-2671" \
  -H "X-API-Key: YOUR_KEY"
```

## GET /v1/validate/card

**Check a payment card number: Luhn checksum, brand and length (nothing is stored)**

Use it to catch typos before a payment form submits. It says nothing about whether the account exists or has funds.

### Parameters

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `number` | query | string | yes | Card number, spaces or dashes allowed Example: 4111 1111 1111 1111 |

### Responses

- `200` OK

```json
{
  "valid": true,
  "luhn": true,
  "brand": "Visa",
  "length": 16,
  "bin": "411111",
  "last4": "1111",
  "masked": "4111 •••• •••• 1111",
  "reason": null
}
```

### Example

```bash
curl "https://api.apialmanac.com/v1/validate/card?number=4111+1111+1111+1111" \
  -H "X-API-Key: YOUR_KEY"
```

## GET /v1/validate/id

**Check an identifier's check digit and format: ISBN, EAN/UPC/GTIN, ISSN, ISIN, CUSIP, SEDOL, VIN, IMEI, ABA routing, NPI, VAT number, Luhn**

### Parameters

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `type` | query | enum | yes | Which identifier One of: isbn, ean, upc, gtin, issn, isin, cusip, sedol, vin, imei, aba, npi |
| `value` | query | string | yes | The identifier, separators allowed Example: 978-0-306-40615-7 |

### Responses

- `200` OK

```json
{
  "type": "isbn",
  "input": "978-0-306-40615-7",
  "normalized": "9780306406157",
  "valid": true,
  "reason": null,
  "format": "ISBN-13",
  "isbn10": "0306406152",
  "isbn13": "9780306406157",
  "prefix": "978"
}
```

### Example

```bash
curl "https://api.apialmanac.com/v1/validate/id?type=isbn&value=978-0-306-40615-7" \
  -H "X-API-Key: YOUR_KEY"
```

# Network

# Dns

## GET /v1/dns

**Resolve a DNS record (A, AAAA, MX, TXT, NS, CNAME, SOA, CAA, SRV) via DNS over HTTPS**

### Parameters

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `name` | query | string | yes | Hostname to resolve Example: cloudflare.com |
| `type` | query | enum | no | Record type One of: A, AAAA, MX, TXT, NS, CNAME, SOA, CAA, SRV, PTR, HTTPS |

### Responses

- `200` OK

```json
{
  "name": "cloudflare.com",
  "type": "MX",
  "status": "NOERROR",
  "dnssec_validated": true,
  "answers": [
    {
      "name": "cloudflare.com",
      "type": "MX",
      "ttl": 300,
      "data": {
        "preference": 10,
        "exchange": "mailstream-east.mxrecord.io"
      }
    },
    {
      "name": "cloudflare.com",
      "type": "MX",
      "ttl": 300,
      "data": {
        "preference": 20,
        "exchange": "mailstream-central.mxrecord.mx"
      }
    }
  ],
  "authority": []
}
```

### Example

```bash
curl "https://api.apialmanac.com/v1/dns?name=cloudflare.com" \
  -H "X-API-Key: YOUR_KEY"
```

# Useragent

## GET /v1/useragent

**Parse a browser User-Agent string into browser, engine, OS and device**

Omit `ua` to parse the User-Agent of the request itself.

### Parameters

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `ua` | query | string | no | User-Agent string Example: Mozilla/5.0 (iPhone; CPU iPhone OS 17_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.5 Mobile/15E148 Safari/604.1 |

### Responses

- `200` OK

```json
{
  "ua": "Mozilla/5.0 (iPhone; CPU iPhone OS 17_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.5 Mobile/15E148 Safari/604.1",
  "browser": {
    "name": "Mobile Safari",
    "version": "17.5",
    "major": "17"
  },
  "engine": {
    "name": "WebKit",
    "version": "605.1.15"
  },
  "os": {
    "name": "iOS",
    "version": "17.5"
  },
  "device": {
    "type": "mobile",
    "vendor": "Apple",
    "model": "iPhone"
  },
  "cpu": {
    "architecture": null
  },
  "bot": false
}
```

### Example

```bash
curl "https://api.apialmanac.com/v1/useragent" \
  -H "X-API-Key: YOUR_KEY"
```

# Text

# Hash

## GET /v1/hash

**MD5, SHA-1, SHA-256, SHA-384 or SHA-512 of a string**

The text is hashed as UTF-8 and never stored. For files, hash locally — this is for short strings and checksums.

### Parameters

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `text` | query | string | yes | Text to hash (UTF-8) Example: hello |
| `algo` | query | enum | no | Algorithm One of: md5, sha1, sha256, sha384, sha512 |
| `encoding` | query | enum | no | Output encoding One of: hex, base64 |

### Responses

- `200` OK

```json
{
  "algo": "sha256",
  "encoding": "hex",
  "length": 5,
  "hash": "2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824"
}
```

### Example

```bash
curl "https://api.apialmanac.com/v1/hash?text=hello" \
  -H "X-API-Key: YOUR_KEY"
```

# Uuid

## GET /v1/uuid

**Generate UUIDs (v4 random or v7 time-ordered)**

### Parameters

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `version` | query | enum | no | 4 = random, 7 = time-ordered (sorts by creation time) One of: 4, 7 |
| `count` | query | integer | no | How many Example: 1 |

### Responses

- `200` OK

```json
{
  "version": 7,
  "count": 2,
  "uuids": [
    "019a1d2e-8f3c-7b10-9c4e-2a6f1b7d8e90",
    "019a1d2e-8f3c-7b11-8d5f-3b7a2c8e9f01"
  ]
}
```

### Example

```bash
curl "https://api.apialmanac.com/v1/uuid" \
  -H "X-API-Key: YOUR_KEY"
```

# Numbers

## GET /v1/numbers/words

**Spell an integer in English words, cardinal or ordinal**

### Parameters

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `n` | query | string | yes | The integer Example: 1234 |
| `ordinal` | query | boolean | no | true → "one thousand two hundred thirty-fourth" Example: False |

### Responses

- `200` OK

```json
{
  "n": "1234",
  "words": "one thousand two hundred thirty-four",
  "ordinal": false
}
```

### Example

```bash
curl "https://api.apialmanac.com/v1/numbers/words?n=1234" \
  -H "X-API-Key: YOUR_KEY"
```

## GET /v1/numbers/roman

**Convert between integers (1–3999) and Roman numerals**

Give `n` to encode or `roman` to decode.

### Parameters

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `n` | query | integer | no | Integer to encode Example: 1994 |
| `roman` | query | string | no | Numeral to decode Example: MCMXCIV |

### Responses

- `200` OK

```json
{
  "n": 1994,
  "roman": "MCMXCIV"
}
```

### Example

```bash
curl "https://api.apialmanac.com/v1/numbers/roman" \
  -H "X-API-Key: YOUR_KEY"
```

# Semver

## GET /v1/semver

**Parse and sort semantic versions, compare two, and test them against an npm-style range**

### Parameters

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `versions` | query | string | yes | Comma-separated versions Example: 1.2.3, 1.10.0, 1.2.3-beta.1, 2.0.0-rc.1, v0.9.9 |
| `range` | query | string | no | Range to test, e.g. ^1.2.0, ~1.2.3, >=1.0.0 <2.0.0, 1.x, 1.2.3 - 1.9.0, >=2 \|\| <1 Example: ^1.2.0 |
| `compare` | query | string | no | Two versions separated by a comma to compare directly Example: 1.10.0,1.9.9 |

### Responses

- `200` OK

```json
{
  "versions": [
    {
      "input": "1.10.0",
      "valid": true,
      "version": "1.10.0",
      "major": 1,
      "minor": 10,
      "patch": 0,
      "prerelease": [],
      "build": []
    },
    {
      "input": "1.2.3-beta.1",
      "valid": true,
      "version": "1.2.3-beta.1",
      "major": 1,
      "minor": 2,
      "patch": 3,
      "prerelease": [
        "beta",
        "1"
      ],
      "build": []
    }
  ],
  "sorted": [
    "1.2.3-beta.1",
    "1.10.0"
  ],
  "lowest": "1.2.3-beta.1",
  "highest": "1.10.0",
  "range": {
    "input": "^1.2.0",
    "matches": [
      "1.10.0"
    ],
    "highest_match": "1.10.0"
  },
  "compare": {
    "a": "1.10.0",
    "b": "1.9.9",
    "result": 1,
    "relation": "1.10.0 > 1.9.9"
  }
}
```

### Example

```bash
curl "https://api.apialmanac.com/v1/semver?versions=1.2.3%2C+1.10.0%2C+1.2.3-beta.1%2C+2.0.0-rc.1%2C+v0.9.9" \
  -H "X-API-Key: YOUR_KEY"
```

# Color

## GET /v1/color

**Parse a color (hex, rgb(), hsl(), CSS name), convert it, name it, and check WCAG contrast against another**

### Parameters

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `value` | query | string | yes | The color Example: #2F6B4F |
| `compare` | query | string | no | A second color for contrast (e.g. the background) Example: #FAF7F0 |

### Responses

- `200` OK

```json
{
  "input": "#2F6B4F",
  "hex": "#2f6b4f",
  "hex_alpha": null,
  "rgb": {
    "r": 47,
    "g": 107,
    "b": 79
  },
  "alpha": 1,
  "css": "rgb(47 107 79)",
  "hsl": {
    "h": 152,
    "s": 39,
    "l": 30,
    "css": "hsl(152 39% 30%)"
  },
  "hsv": {
    "h": 152,
    "s": 56,
    "v": 42
  },
  "cmyk": {
    "c": 56,
    "m": 0,
    "y": 26,
    "k": 58
  },
  "luminance": 0.11,
  "is_dark": true,
  "text_on_it": "#ffffff",
  "name": null,
  "nearest_named": {
    "name": "seagreen",
    "hex": "#2e8b57",
    "distance": 19.6,
    "metric": "CIE76 ΔE"
  },
  "complementary": "#6b2f4b",
  "contrast": {
    "with": "#faf7f0",
    "ratio": 5.68,
    "aa_normal_text": true,
    "aa_large_text": true,
    "aaa_normal_text": false,
    "aaa_large_text": true
  }
}
```

### Example

```bash
curl "https://api.apialmanac.com/v1/color?value=%232F6B4F" \
  -H "X-API-Key: YOUR_KEY"
```

# Reference

# Countries

## GET /v1/countries

**All countries and territories (ISO 3166) with capital, region, currencies, dial codes and flag**

### Parameters

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `q` | query | string | no | Substring of the name Example: island |
| `region` | query | string | no | Africa, Americas, Asia, Europe or Oceania Example: Europe |
| `subregion` | query | string | no | e.g. Western Europe, Caribbean Example: string |
| `continent` | query | string | no | AF, AN, AS, EU, NA, OC or SA Example: string |
| `currency` | query | string | no | Only countries using this ISO 4217 currency Example: EUR |
| `independent` | query | boolean | no | true for sovereign states only, false for territories only Example: True |

### Responses

- `200` OK

```json
{
  "count": 1,
  "countries": [
    {
      "code": "FR",
      "alpha3": "FRA",
      "numeric": "250",
      "name": "France",
      "official_name": "the French Republic",
      "capital": "Paris",
      "continent": "EU",
      "region": "Europe",
      "subregion": "Western Europe",
      "intermediate_region": null,
      "currencies": [
        "EUR"
      ],
      "currency_names": [
        "Euro"
      ],
      "calling_codes": [
        "33"
      ],
      "tld": ".fr",
      "languages": [
        "fr-FR",
        "frp",
        "br",
        "co",
        "ca",
        "eu",
        "oc"
      ],
      "flag": "🇫🇷",
      "independent": true,
      "landlocked": false,
      "least_developed": false,
      "small_island": false,
      "fips": "FR",
      "ioc": "FRA",
      "fifa": "FRA",
      "geoname_id": 3017382,
      "wikidata": "Q142"
    }
  ]
}
```

### Example

```bash
curl "https://api.apialmanac.com/v1/countries" \
  -H "X-API-Key: YOUR_KEY"
```

## GET /v1/countries/{code}

**One country by ISO alpha-2, alpha-3, numeric code or exact name**

### Parameters

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `code` | path | string | yes | FR, FRA, 250 or France Example: FR |

### Responses

- `200` OK

```json
{
  "code": "FR",
  "alpha3": "FRA",
  "numeric": "250",
  "name": "France",
  "official_name": "the French Republic",
  "capital": "Paris",
  "continent": "EU",
  "region": "Europe",
  "subregion": "Western Europe",
  "intermediate_region": null,
  "currencies": [
    "EUR"
  ],
  "currency_names": [
    "Euro"
  ],
  "calling_codes": [
    "33"
  ],
  "tld": ".fr",
  "languages": [
    "fr-FR",
    "frp",
    "br",
    "co",
    "ca",
    "eu",
    "oc"
  ],
  "flag": "🇫🇷",
  "independent": true,
  "landlocked": false,
  "least_developed": false,
  "small_island": false,
  "fips": "FR",
  "ioc": "FRA",
  "fifa": "FRA",
  "geoname_id": 3017382,
  "wikidata": "Q142"
}
```

### Example

```bash
curl "https://api.apialmanac.com/v1/countries/FR" \
  -H "X-API-Key: YOUR_KEY"
```

# Currencies

## GET /v1/currencies

**ISO 4217 currencies in circulation with minor units, symbols and where they are used**

### Parameters

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `q` | query | string | no | Substring of the name or an entity using it Example: dollar |
| `kind` | query | enum | no | `special` = funds, metals and test codes (X…) One of: currency, special |

### Responses

- `200` OK

```json
{
  "count": 1,
  "currencies": [
    {
      "code": "EUR",
      "name": "Euro",
      "numeric": "978",
      "minor_unit": 2,
      "symbol": "€",
      "kind": "currency",
      "entities": [
        "Andorra",
        "Austria",
        "Belgium"
      ]
    }
  ]
}
```

### Example

```bash
curl "https://api.apialmanac.com/v1/currencies" \
  -H "X-API-Key: YOUR_KEY"
```

## GET /v1/currencies/{code}

**One currency by ISO 4217 code**

### Parameters

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `code` | path | string | yes | ISO 4217 alphabetic code Example: JPY |

### Responses

- `200` OK

```json
{
  "code": "JPY",
  "name": "Yen",
  "numeric": "392",
  "minor_unit": 0,
  "symbol": "¥",
  "kind": "currency",
  "entities": [
    "Japan"
  ]
}
```

### Example

```bash
curl "https://api.apialmanac.com/v1/currencies/JPY" \
  -H "X-API-Key: YOUR_KEY"
```

# Languages

## GET /v1/languages

**ISO 639 languages with two- and three-letter codes**

### Parameters

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `q` | query | string | no | Substring of the English name Example: chin |

### Responses

- `200` OK

```json
{
  "count": 1,
  "languages": [
    {
      "alpha2": "fr",
      "alpha3": "fra",
      "alpha3_b": "fre",
      "name": "French",
      "aliases": [],
      "french": "français"
    }
  ]
}
```

### Example

```bash
curl "https://api.apialmanac.com/v1/languages" \
  -H "X-API-Key: YOUR_KEY"
```

## GET /v1/languages/{code}

**One language by ISO 639-1 (fr) or 639-2 (fra / fre) code**

### Parameters

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `code` | path | string | yes | Two- or three-letter code Example: fr |

### Responses

- `200` OK

```json
{
  "alpha2": "fr",
  "alpha3": "fra",
  "alpha3_b": "fre",
  "name": "French",
  "aliases": [],
  "french": "français"
}
```

### Example

```bash
curl "https://api.apialmanac.com/v1/languages/fr" \
  -H "X-API-Key: YOUR_KEY"
```

# Naics

## GET /v1/naics

**Search NAICS 2022 industry codes by title, or list a level (2 = sectors … 6 = national industries)**

Without `q` or `level`, returns the 20 two-digit sectors.

### Parameters

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `q` | query | string | no | Words in the industry title Example: software |
| `level` | query | integer | no | Code length to return Example: 2 |
| `limit` | query | integer | no | Maximum results Example: 50 |

### Responses

- `200` OK

```json
{
  "count": 2,
  "total": 2,
  "industries": [
    {
      "code": "511210",
      "title": "Software Publishers",
      "level": 6
    },
    {
      "code": "5112",
      "title": "Software Publishers",
      "level": 4
    }
  ]
}
```

### Example

```bash
curl "https://api.apialmanac.com/v1/naics" \
  -H "X-API-Key: YOUR_KEY"
```

## GET /v1/naics/{code}

**One NAICS code with its parents up to the sector and its direct children**

### Parameters

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `code` | path | string | yes | NAICS code Example: 541511 |

### Responses

- `200` OK

```json
{
  "code": "541511",
  "title": "Custom Computer Programming Services",
  "level": 6,
  "parents": [
    {
      "code": "54",
      "title": "Professional, Scientific, and Technical Services",
      "level": 2
    },
    {
      "code": "541",
      "title": "Professional, Scientific, and Technical Services",
      "level": 3
    },
    {
      "code": "5415",
      "title": "Computer Systems Design and Related Services",
      "level": 4
    },
    {
      "code": "54151",
      "title": "Computer Systems Design and Related Services",
      "level": 5
    }
  ],
  "children": []
}
```

### Example

```bash
curl "https://api.apialmanac.com/v1/naics/541511" \
  -H "X-API-Key: YOUR_KEY"
```

# Locale

## GET /v1/locale

**How a locale writes things: first day of week, weekend, 12/24-hour clock, number and currency formats, date patterns, text direction**

Pass `currency` to see money formatting, `amount` and `date` to format your own values. Everything comes from CLDR via the runtime.

### Parameters

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `tag` | query | string | yes | BCP 47 locale tag Example: de-DE |
| `currency` | query | string | no | Currency to format (default: the region's) Example: EUR |
| `amount` | query | number | no | Number to format in the examples (default 1234567.891) Example: 1.5 |
| `date` | query | string | no | Date to format in the examples Example: string |

### Responses

- `200` OK

```json
{
  "tag": "de-DE",
  "language": "de",
  "script": "Latn",
  "region": "DE",
  "likely_subtags": "de-Latn-DE",
  "direction": "ltr",
  "week": {
    "first_day": "Monday",
    "first_day_iso": 1,
    "weekend": [
      "Saturday",
      "Sunday"
    ],
    "minimal_days_in_first_week": 4
  },
  "hour_cycle": "h23",
  "calendars": [
    "gregory"
  ],
  "numbering_systems": [
    "latn"
  ],
  "measurement_system": "metric",
  "paper_size": "A4",
  "number": {
    "example": "1.234.567,891",
    "decimal_separator": ",",
    "group_separator": ".",
    "numbering_system": "latn",
    "percent_example": "25,6 %",
    "compact_example": "1,2 Mio."
  },
  "currency": {
    "currency": "EUR",
    "example": "1.234.567,89 €",
    "symbol": "€",
    "symbol_position": "after",
    "accounting_negative": "-1.234.567,89 €",
    "minor_units": 2
  },
  "dates": {
    "short": {
      "pattern": "dd.MM.yy",
      "example": "09.10.26"
    },
    "medium": {
      "pattern": "dd.MM.yyyy",
      "example": "09.10.2026"
    },
    "long": {
      "example": "9. Oktober 2026"
    },
    "full": {
      "example": "Freitag, 9. Oktober 2026"
    },
    "time_short": "14:30",
    "uses_12_hour_clock": false
  },
  "names": {
    "language": {
      "english": "German",
      "native": "Deutsch"
    },
    "region": {
      "code": "DE",
      "english": "Germany",
      "native": "Deutschland"
    },
    "script": {
      "code": "Latn",
      "english": "Latin"
    }
  }
}
```

### Example

```bash
curl "https://api.apialmanac.com/v1/locale?tag=de-DE" \
  -H "X-API-Key: YOUR_KEY"
```

# Places

# Airports

## GET /v1/airports

**Find airports by IATA or ICAO code, country, or a word in the name or city**

At least one filter is required; results are capped by `limit`. Large airports with scheduled service sort first.

### Parameters

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `iata` | query | string | no | IATA code Example: JFK |
| `icao` | query | string | no | ICAO code Example: KJFK |
| `country` | query | string | no | ISO 3166-1 alpha-2 Example: US |
| `q` | query | string | no | Substring of the airport name or city Example: new york |
| `type` | query | enum | no | Airport size class One of: large, medium, small |
| `limit` | query | integer | no | Maximum results Example: 20 |

### Responses

- `200` OK

```json
{
  "count": 1,
  "total": 1,
  "airports": [
    {
      "iata": "JFK",
      "icao": "KJFK",
      "name": "John F Kennedy International Airport",
      "type": "large",
      "city": "New York",
      "country": "US",
      "region": "US-NY",
      "continent": "NA",
      "lat": 40.63975,
      "lon": -73.77893,
      "elevation_ft": 13,
      "scheduled_service": true
    }
  ]
}
```

### Example

```bash
curl "https://api.apialmanac.com/v1/airports" \
  -H "X-API-Key: YOUR_KEY"
```

## GET /v1/airports/{code}

**One airport by IATA (3 letters) or ICAO (4 letters) code**

### Parameters

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `code` | path | string | yes | IATA or ICAO code Example: LHR |

### Responses

- `200` OK

```json
{
  "iata": "JFK",
  "icao": "KJFK",
  "name": "John F Kennedy International Airport",
  "type": "large",
  "city": "New York",
  "country": "US",
  "region": "US-NY",
  "continent": "NA",
  "lat": 40.63975,
  "lon": -73.77893,
  "elevation_ft": 13,
  "scheduled_service": true
}
```

### Example

```bash
curl "https://api.apialmanac.com/v1/airports/LHR" \
  -H "X-API-Key: YOUR_KEY"
```

# Postal

## GET /v1/postal/us/{zip}

**City, state, county and coordinates for a US ZIP code**

ZIP+4 is accepted; the +4 is ignored.

### Parameters

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `zip` | path | string | yes | ZIP code Example: 10001 |

### Responses

- `200` OK

```json
{
  "postal_code": "10001",
  "country": "US",
  "city": "New York",
  "state": "New York",
  "state_code": "NY",
  "county": "New York",
  "lat": 40.7484,
  "lon": -73.9967,
  "attribution": "Postal code data © GeoNames (geonames.org), CC BY 4.0"
}
```

### Example

```bash
curl "https://api.apialmanac.com/v1/postal/us/10001" \
  -H "X-API-Key: YOUR_KEY"
```

# Cities

## GET /v1/cities

**Find cities by name: coordinates, population, time zone and the local time there now**

Cities of 15,000+ people worldwide. Name matches are prefix first, then substring; results are ordered by population, so `q=paris` puts Paris, France before Paris, Texas. Add `country` to narrow.

### Parameters

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `q` | query | string | yes | City name (any script; ASCII spellings work too) Example: denver |
| `country` | query | string | no | ISO 3166-1 alpha-2 Example: US |
| `limit` | query | integer | no | Maximum results Example: 10 |

### Responses

- `200` OK

```json
{
  "count": 1,
  "total": 1,
  "cities": [
    {
      "id": 5419384,
      "name": "Denver",
      "ascii_name": "Denver",
      "country": "US",
      "admin1": "Colorado",
      "admin1_code": "CO",
      "lat": 39.7392,
      "lon": -104.9847,
      "population": 715522,
      "elevation_m": 1609,
      "timezone": "America/Denver",
      "offset": "-06:00",
      "abbreviation": "MDT",
      "local_time": "2026-10-09T10:30:00-06:00"
    }
  ],
  "attribution": "City data © GeoNames (geonames.org), CC BY 4.0"
}
```

### Example

```bash
curl "https://api.apialmanac.com/v1/cities?q=denver" \
  -H "X-API-Key: YOUR_KEY"
```

## GET /v1/cities/nearest

**Nearest cities to a coordinate, with distance and time zone (a coarse reverse geocode)**

Cities of 15,000+ people only, so remote coordinates return the nearest town some distance away; `distance_km` says how far.

### Parameters

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `lat` | query | number | yes | Latitude Example: 40.6413 |
| `lon` | query | number | yes | Longitude Example: -73.7781 |
| `limit` | query | integer | no | How many Example: 5 |

### Responses

- `200` OK

```json
{
  "query": {
    "lat": 40.6413,
    "lon": -73.7781
  },
  "count": 1,
  "cities": [
    {
      "id": 5125771,
      "name": "Jamaica",
      "ascii_name": "Jamaica",
      "country": "US",
      "admin1": "New York",
      "admin1_code": "NY",
      "lat": 40.6915,
      "lon": -73.8057,
      "population": 216866,
      "elevation_m": 11,
      "timezone": "America/New_York",
      "offset": "-04:00",
      "abbreviation": "EDT",
      "local_time": "2026-10-09T12:30:00-04:00",
      "distance_km": 6.1,
      "bearing": 338
    }
  ],
  "attribution": "City data © GeoNames (geonames.org), CC BY 4.0"
}
```

### Example

```bash
curl "https://api.apialmanac.com/v1/cities/nearest?lat=40.6413&lon=-73.7781" \
  -H "X-API-Key: YOUR_KEY"
```

## GET /v1/cities/{id}

**One city by its GeoNames id**

### Parameters

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `id` | path | integer | yes | GeoNames id Example: 5419384 |

### Responses

- `200` OK

```json
{
  "id": 5419384,
  "name": "Denver",
  "ascii_name": "Denver",
  "country": "US",
  "admin1": "Colorado",
  "admin1_code": "CO",
  "lat": 39.7392,
  "lon": -104.9847,
  "population": 715522,
  "elevation_m": 1609,
  "timezone": "America/Denver",
  "offset": "-06:00",
  "abbreviation": "MDT",
  "local_time": "2026-10-09T10:30:00-06:00",
  "attribution": "City data © GeoNames (geonames.org), CC BY 4.0"
}
```

### Example

```bash
curl "https://api.apialmanac.com/v1/cities/5419384" \
  -H "X-API-Key: YOUR_KEY"
```

# Geo

## GET /v1/geo/distance

**Great-circle distance, bearings, midpoint and bounding box between two coordinates**

Give `lat2`/`lon2` for a second point, or `bearing` and `distance_km` to project from the first point instead. `radius_km` adds a bounding box around the first point, handy for "within 25 km" searches.

### Parameters

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `lat1` | query | number | yes | First point latitude Example: 40.7128 |
| `lon1` | query | number | yes | First point longitude Example: -74.006 |
| `lat2` | query | number | no | Second point latitude Example: 51.5074 |
| `lon2` | query | number | no | Second point longitude Example: -0.1278 |
| `bearing` | query | number | no | Projection: initial bearing in degrees Example: 0 |
| `distance_km` | query | number | no | Projection: distance to travel Example: 0 |
| `radius_km` | query | number | no | Bounding box radius around the first point Example: 0 |

### Responses

- `200` OK

```json
{
  "from": {
    "lat": 40.7128,
    "lon": -74.006
  },
  "to": {
    "lat": 51.5074,
    "lon": -0.1278
  },
  "distance": {
    "km": 5570.2,
    "mi": 3461.2,
    "nmi": 3007.7,
    "m": 5570222
  },
  "initial_bearing": 51.2,
  "final_bearing": 108.3,
  "compass": "NE",
  "midpoint": {
    "lat": 52.3,
    "lon": -41.7
  },
  "bounding_box": {
    "south": 40.7128,
    "north": 51.5074,
    "west": -74.006,
    "east": -0.1278
  },
  "note": "great-circle on a sphere of radius 6371.0088 km"
}
```

### Example

```bash
curl "https://api.apialmanac.com/v1/geo/distance?lat1=40.7128&lon1=-74.006" \
  -H "X-API-Key: YOUR_KEY"
```

# Finance

# Fx

## GET /v1/fx

**Daily exchange rates for ~30 currencies (ECB reference rates), rebased to any of them**

### Parameters

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `base` | query | string | no | Base currency Example: USD |
| `symbols` | query | string | no | Only these currencies Example: EUR,GBP,JPY |

### Responses

- `200` OK

```json
{
  "base": "USD",
  "date": "2026-10-07",
  "rates": {
    "EUR": 0.8531,
    "GBP": 0.7452,
    "JPY": 149.21
  },
  "count": 3,
  "source": "European Central Bank euro foreign exchange reference rates (ecb.europa.eu). Indicative only."
}
```

### Example

```bash
curl "https://api.apialmanac.com/v1/fx" \
  -H "X-API-Key: YOUR_KEY"
```

## GET /v1/fx/convert

**Convert an amount between two currencies at the latest ECB reference rate**

### Parameters

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `amount` | query | number | yes | Amount in `from` Example: 100 |
| `from` | query | string | yes | Currency of `amount` Example: USD |
| `to` | query | string | yes | Currency to convert into Example: EUR |

### Responses

- `200` OK

```json
{
  "amount": 100,
  "from": "USD",
  "to": "EUR",
  "rate": 0.8531,
  "result": 85.31,
  "date": "2026-10-07",
  "source": "European Central Bank euro foreign exchange reference rates (ecb.europa.eu). Indicative only."
}
```

### Example

```bash
curl "https://api.apialmanac.com/v1/fx/convert?amount=100&from=USD&to=EUR" \
  -H "X-API-Key: YOUR_KEY"
```

# Markets

## GET /v1/markets

**Is a market open right now? Session, next open and close, holidays and early closes (NYSE, NASDAQ, LSE, ECB, B3)**

Regular sessions only, no pre- or after-hours. ECB means TARGET2 business days, which is what euro settlement and most European contracts key on.

### Parameters

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `market` | query | enum | yes | Market code One of: NYSE, NASDAQ, LSE, ECB, B3 |
| `at` | query | string | no | ISO-8601 instant to evaluate (default now) Example: 2026-11-27T18:30:00Z |

### Responses

- `200` OK

```json
{
  "market": "NYSE",
  "name": "New York Stock Exchange",
  "timezone": "America/New_York",
  "at": {
    "utc": "2026-11-27T18:30:00Z",
    "local": "2026-11-27T13:30:00-05:00"
  },
  "status": "closed",
  "reason": "after the early close (Day after Thanksgiving)",
  "session": {
    "date": "2026-11-27",
    "open": {
      "utc": "2026-11-27T14:30:00Z",
      "local": "2026-11-27T09:30:00-05:00"
    },
    "close": {
      "utc": "2026-11-27T18:00:00Z",
      "local": "2026-11-27T13:00:00-05:00"
    },
    "early_close": "Day after Thanksgiving"
  },
  "next_open": {
    "utc": "2026-11-30T14:30:00Z",
    "local": "2026-11-30T09:30:00-05:00"
  },
  "next_close": {
    "utc": "2026-11-30T21:00:00Z",
    "local": "2026-11-30T16:00:00-05:00"
  },
  "previous_close": {
    "utc": "2026-11-27T18:00:00Z",
    "local": "2026-11-27T13:00:00-05:00"
  },
  "regular_hours": "09:30–16:00 America/New_York",
  "source": "python-holidays financial calendar NYSE"
}
```

### Example

```bash
curl "https://api.apialmanac.com/v1/markets?market=NYSE" \
  -H "X-API-Key: YOUR_KEY"
```

# Loan

## GET /v1/loan

**Monthly payment, total interest, yearly summary and optional full schedule for a loan or mortgage**

`rate` is the annual percentage rate. Give `years` or `months`. `extra` is an additional principal payment each month; `start` dates the schedule.

### Parameters

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `principal` | query | number | yes | Amount borrowed Example: 400000 |
| `rate` | query | number | yes | Annual interest rate, percent Example: 6.25 |
| `years` | query | number | no | Term in years Example: 30 |
| `months` | query | integer | no | Term in months (overrides years) Example: 1 |
| `extra` | query | number | no | Extra principal paid every month Example: 0 |
| `start` | query | string | no | Date of the first payment Example: string |
| `schedule` | query | boolean | no | Include every monthly row (up to 1,200) Example: False |

### Responses

- `200` OK

```json
{
  "principal": 400000,
  "rate": 6.25,
  "months": 360,
  "payment": 2462.87,
  "total_paid": 886633.2,
  "total_interest": 486633.2,
  "extra": 0,
  "payoff_months": 360,
  "payoff_date": null,
  "yearly": [
    {
      "year": 1,
      "paid": 29554.44,
      "principal": 4694.14,
      "interest": 24860.3,
      "balance": 395305.86
    }
  ],
  "schedule": []
}
```

### Example

```bash
curl "https://api.apialmanac.com/v1/loan?principal=400000&rate=6.25" \
  -H "X-API-Key: YOUR_KEY"
```
