CycleCalcs Dark Window API

The Dark Window API from CycleCalcs — 1 operation(s) for dark window.

OpenAPI Specification

cyclecalcs-dark-window-api-openapi.yml Raw ↑
openapi: 3.2.0
info:
  title: CycleCalcs Astronomy Dark Window API
  version: 2.0.0
  description: 'A read-only astronomy API that returns the named answer and the numbers behind it, with the frame, epoch, time scale and refraction model stated on every response. It reports angles, times and names, and attaches no meaning to any of them. Computed in real time with the MIT-licensed Astronomy Engine. This document is generated from the shipped route table (netlify/lib/v2/registry.mjs) by tools/generate-openapi.mjs, so it cannot list a route, a parameter or a requirement the API does not actually enforce. Computed astronomical output is unrestricted: use, store, redistribute and sell it without attribution. The one exception is GeoNames place data served by GET /v2/places and by any response that resolved a `place` parameter, which requires the credit line in meta.attribution; see GET /v2/attribution for the full source register.'
  license:
    name: Computed output unrestricted; third-party data credited per response
    url: https://www.cyclecalcs.com/api/terms.html
  termsOfService: https://www.cyclecalcs.com/api/terms.html
  contact:
    name: CycleCalcs
    email: info@cyclecalcs.com
    url: https://www.cyclecalcs.com/api.html
servers:
- url: https://www.cyclecalcs.com
security:
- {}
- RapidAPIKey: []
tags:
- name: Dark Window
paths:
  /v2/dark-window:
    get:
      operationId: getDarkWindow
      summary: 'The genuinely dark moonless observing window of a night: astronomical night intersected with the Moon being down, ranked across up to 62 nights with a trend'
      description: 'The genuinely dark moonless observing window of a night: astronomical night intersected with the Moon being down, ranked across up to 62 nights with a trend. Formats: json, csv. Example: GET /v2/dark-window?lat=51.509&lon=-0.126&at=2026-11-14&tz=Europe/London&nights=3'
      parameters:
      - name: at
        in: query
        required: false
        description: 'The instant to evaluate. ISO 8601: a date (2026-06-21), or a date and time with an optional seconds, fraction and either Z or a numeric UTC offset. No offset and no `tz` reads as UTC. Reliable from 1700 to 2200.'
        schema:
          type: string
        example: '2026-11-14'
      - $ref: '#/components/parameters/LatitudeRequiredParam'
      - $ref: '#/components/parameters/LongitudeRequiredParam'
      - $ref: '#/components/parameters/ElevationMParam'
      - $ref: '#/components/parameters/PlaceParam'
      - $ref: '#/components/parameters/PlaceStrategyParam'
      - name: nights
        in: query
        required: false
        description: How many consecutive local nights to rank, starting the night `at` falls in.
        schema:
          type: integer
          minimum: 1
          maximum: 62
        example: 3
      - name: sun_depression_deg
        in: query
        required: false
        description: The solar depression angle, in degrees, that defines "dark" for this request. Default 18 (astronomical night).
        schema:
          type: number
          minimum: 6
          maximum: 30
        example: 18
      - name: moon_altitude_max_deg
        in: query
        required: false
        description: The Moon must be at or below this altitude, in degrees, to count as "down". Default 0.
        schema:
          type: number
          minimum: -90
          maximum: 90
        example: 0
      - name: moon_illumination_max
        in: query
        required: false
        description: Treat the Moon as "down" whenever its illuminated fraction is at or below this value, whatever its altitude. Default 1 (illumination never overrides altitude).
        schema:
          type: number
          minimum: 0
          maximum: 1
        example: 0.15
      - $ref: '#/components/parameters/TzParam'
      - $ref: '#/components/parameters/AmbiguousParam'
      - $ref: '#/components/parameters/NonexistentParam'
      - $ref: '#/components/parameters/TimeFormatParam'
      - $ref: '#/components/parameters/FormatParam'
      - $ref: '#/components/parameters/FieldsParam'
      - $ref: '#/components/parameters/ShapeParam'
      - $ref: '#/components/parameters/PrecisionParam'
      - $ref: '#/components/parameters/PrettyParam'
      - $ref: '#/components/parameters/VerbosityParam'
      responses:
        '200':
          description: The answer.
          headers:
            ETag:
              description: Present when the cache class is deterministic or time-quantised. Send back as If-None-Match to get 304.
              schema:
                type: string
            Cache-Control:
              description: Browser caching directive for this response's cache class.
              schema:
                type: string
            RateLimit:
              description: draft-ietf-httpapi-ratelimit-headers usage for the current window.
              schema:
                type: string
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Envelope'
              examples:
                live:
                  summary: GET /v2/dark-window?lat=51.509&lon=-0.126&at=2026-11-14&tz=Europe/London&nights=3
                  description: A real request to the running API, not a hand-written mock. It needs no key and can be opened directly, so the example is whatever the endpoint actually returns today.
                  externalValue: https://www.cyclecalcs.com/v2/dark-window?lat=51.509&lon=-0.126&at=2026-11-14&tz=Europe/London&nights=3
            text/csv:
              schema:
                type: string
                description: A CSV rendering of the same answer. See meta and the CSV header comment for provenance.
              examples:
                live:
                  summary: GET /v2/dark-window?lat=51.509&lon=-0.126&at=2026-11-14&tz=Europe/London&nights=3&format=csv
                  description: A real request to the running API, not a hand-written mock. It needs no key and can be opened directly, so the example is whatever the endpoint actually returns today.
                  externalValue: https://www.cyclecalcs.com/v2/dark-window?lat=51.509&lon=-0.126&at=2026-11-14&tz=Europe/London&nights=3&format=csv
        '304':
          description: Not Modified. Returned when If-None-Match matches the current ETag. No body.
        '400':
          description: 'The request could not be understood: a malformed or out-of-range parameter, an incomplete range, a conflicting pair of parameters, or a request too large for the compute budget.'
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '404':
          description: 'Not found: a `place`/`id`/target that does not resolve to anything, or a path this API does not serve.'
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '405':
          description: Method not allowed. This API serves GET, HEAD and OPTIONS only.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '413':
          description: The serialised response exceeded the hard size cap. Narrow the request with `fields`, verbosity=compact or a smaller range.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
        '429':
          description: Rate limited. Wait the number of seconds in Retry-After, or cache the response.
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
      tags:
      - Dark Window
components:
  parameters:
    TzParam:
      name: tz
      in: query
      required: false
      description: An IANA time zone name, for example Europe/London or America/Chicago. Numeric offsets and abbreviations are not accepted. Governs how a date-only or offset-free `at`/`start`/`end` is read, and how local instants are rendered when time_format=iso.
      schema:
        type: string
      example: Europe/London
    PlaceParam:
      name: place
      in: query
      required: false
      description: A place name (place=London), a name with a country (place=Cambridge,GB), or a stable identifier from GET /v2/places (place=id:us-n35198-w111651). Supplies lat, lon and, unless tz is also sent, the time zone. Mutually exclusive with sending lat and lon directly. Withheld unless GET /v2 reports capabilities.place_lookup true.
      schema:
        type: string
      example: London
    AmbiguousParam:
      name: ambiguous
      in: query
      required: false
      description: How to resolve a local time that a clock repeated, such as the return from daylight saving. error refuses with 409 AMBIGUOUS_LOCAL_TIME.
      schema:
        type: string
        enum:
        - first
        - last
        - error
        default: first
      example: first
    PrecisionParam:
      name: precision
      in: query
      required: false
      description: Decimal places for numeric fields.
      schema:
        type: integer
        minimum: 0
        maximum: 9
        default: 6
      example: 6
    PlaceStrategyParam:
      name: place_strategy
      in: query
      required: false
      description: best guesses the intended place when a name is ambiguous and reports the guess as a warning. error refuses an ambiguous name with 400 AMBIGUOUS_PLACE and the candidates in `supported`. Only meaningful with `place`.
      schema:
        type: string
        enum:
        - best
        - error
        default: best
      example: best
    LongitudeRequiredParam:
      name: lon
      in: query
      required: true
      description: Longitude in decimal degrees, east positive. No compass suffix (do not append E or W). Required together with lat, or neither.
      schema:
        type: number
        minimum: -180
        maximum: 180
      example: -0.0015
    ShapeParam:
      name: shape
      in: query
      required: false
      description: nested returns the documented object tree. flat returns one object with dotted keys, format=json only.
      schema:
        type: string
        enum:
        - nested
        - flat
        default: nested
      example: nested
    NonexistentParam:
      name: nonexistent
      in: query
      required: false
      description: How to resolve a local time that never happened, such as inside a spring-forward gap. error refuses with 400 NONEXISTENT_LOCAL_TIME.
      schema:
        type: string
        enum:
        - error
        - shift_forward
        - shift_back
        default: error
      example: error
    FormatParam:
      name: format
      in: query
      required: false
      description: Response representation. Each endpoint serves a subset of json, csv and txt; see that operation's description for the exact list, or GET /v2 for every endpoint's formats array. An unsupported value is 400 BAD_FORMAT with the accepted list in `supported`.
      schema:
        type: string
      example: json
    FieldsParam:
      name: fields
      in: query
      required: false
      description: Comma-separated dot paths into `data` (for example moon.phase_name,moon.illumination) so only those fields are returned. Up to 64 paths; an array element is addressed by its object key, never by index.
      schema:
        type: string
    LatitudeRequiredParam:
      name: lat
      in: query
      required: true
      description: Latitude in decimal degrees, north positive. No compass suffix (do not append N or S). Required together with lon, or neither.
      schema:
        type: number
        minimum: -90
        maximum: 90
      example: 51.4778
    VerbosityParam:
      name: verbosity
      in: query
      required: false
      description: full includes prose notes, frame definitions and withheld-field reasons in meta. compact keeps every value and every machine-readable name and drops the prose.
      schema:
        type: string
        enum:
        - full
        - compact
        default: full
      example: full
    TimeFormatParam:
      name: time_format
      in: query
      required: false
      description: 'How instants are rendered: iso for ISO 8601 strings carrying the effective offset, or unix for integer seconds since the epoch.'
      schema:
        type: string
        enum:
        - iso
        - unix
        default: iso
      example: iso
    PrettyParam:
      name: pretty
      in: query
      required: false
      description: Whether the JSON body is indented (1) or compact (0). Has no effect on csv or txt.
      schema:
        type: integer
        enum:
        - 0
        - 1
        default: 1
      example: 1
    ElevationMParam:
      name: elevation_m
      in: query
      required: false
      description: Observer elevation above mean sea level, in metres. Raises the observer on a locally flat plateau; sea-horizon dip is not modelled.
      schema:
        type: number
        minimum: -500
        maximum: 9000
        default: 0
      example: 11
  schemas:
    Envelope:
      type: object
      description: The nine-key v2 response envelope. Every /v2 endpoint returns exactly these keys, in this order, on every 200 (spec-00 1.1).
      required:
      - endpoint
      - computed_at
      - query
      - data
      - warnings
      - links
      - meta
      - attribution
      - docs
      properties:
        endpoint:
          type: string
          description: The endpoint path that produced this response.
          example: /v2/sun
        computed_at:
          type: string
          format: date-time
          description: 'A revision stamp, never a wall clock: identical requests return identical bytes, so a fixed_instant or reference response can be cached for a year and 304 stays reachable.'
          example: '2026-08-01T00:00:00.000Z'
        query:
          type: object
          description: 'The request as understood: every resolved input (instant, location, presentation options) plus `ignored`, in the order spec-00 13.2 defines. Shape is endpoint-specific.'
          additionalProperties: true
        data:
          description: The answer. Shape is endpoint-specific; see each operation's summary and /api/reference.html.
        warnings:
          type: array
          description: Machine-readable notices about this response. Empty when none apply; never changes the HTTP status.
          items:
            $ref: '#/components/schemas/Warning'
        links:
          type: object
          description: Related URLs. self reproduces this exact response; docs is always present; others (page, spec, next, first, explain) appear where relevant.
          additionalProperties:
            type: string
            format: uri
          example:
            self: https://www.cyclecalcs.com/v2/sun?at=2026-06-21&lat=51.4778&lon=-0.0015
            docs: https://www.cyclecalcs.com/api/reference.html#sun
            spec: https://www.cyclecalcs.com/v2/openapi.json
            page: https://www.cyclecalcs.com/sunrise-sunset-calculator.html
            explain: https://www.cyclecalcs.com/learn/seasons.html
        meta:
          type: object
          description: 'Provenance: engine version, rights and attribution, cache class, accuracy statement, tzdb version, and endpoint-specific conventions (refraction model, horizon definitions, time scales, and so on). Never subject to `fields` projection.'
          additionalProperties: true
        attribution:
          type: string
          description: The credit line, byte-identical to meta.attribution.text.
          example: Computed by CycleCalcs (cyclecalcs.com) with the MIT-licensed Astronomy Engine. Positional astronomy only.
        docs:
          type: string
          format: uri
          description: The human-readable reference section for this endpoint.
          example: https://www.cyclecalcs.com/api/reference.html#sun
    Problem:
      type: object
      description: An RFC 9457 problem detail document. Served on every non-2xx v2 response with Content-Type application/problem+json.
      required:
      - type
      - title
      - status
      - detail
      - code
      - parameter
      - hint
      - example
      - supported
      - request_id
      - error_chain
      - docs
      properties:
        type:
          type: string
          format: uri
          description: 'A URI identifying the error type, ending in a #fragment matching `code` in kebab-case. Dereferenceable at /api/errors.html.'
          example: https://www.cyclecalcs.com/api/errors.html#bad-latitude
        title:
          type: string
          description: A short, fixed, human-readable summary of the error type (not the instance).
          example: Latitude is not a number from -90 to 90
        status:
          type: integer
          enum:
          - 400
          - 401
          - 404
          - 405
          - 406
          - 409
          - 410
          - 413
          - 414
          - 422
          - 429
          - 500
          - 503
          description: The HTTP status code, repeated from the response line.
          example: 400
        detail:
          type: string
          description: A human-readable explanation specific to this occurrence.
          example: lat must be a number from -90 to 90; got "999".
        instance:
          type: string
          format: uri
          description: 'Present only on non-cacheable statuses (429, 503, and unexpected 500s): `type` with ?request_id=<id> inserted before its #fragment.'
          example: https://www.cyclecalcs.com/api/errors.html?request_id=ba0c53d302f09df4#rate-limited
        code:
          type: string
          enum:
          - AMBIGUOUS_LOCAL_TIME
          - AMBIGUOUS_LONGITUDE_FORMAT
          - AMBIGUOUS_PLACE
          - BAD_ALARM
          - BAD_APERTURE
          - BAD_BOOLEAN
          - BAD_BORTLE
          - BAD_CALENDAR_SOURCE
          - BAD_CLIENT
          - BAD_COUNT
          - BAD_CURSOR
          - BAD_CYCLE_KEY
          - BAD_DATE
          - BAD_DEPRESSION
          - BAD_ECLIPSE_DIRECTION
          - BAD_ECLIPSE_TYPE
          - BAD_ELEVATION
          - BAD_FIELDS
          - BAD_FORMAT
          - BAD_HEIGHT_OF_EYE
          - BAD_HEMISPHERE
          - BAD_INCLUDE
          - BAD_INDEX_ERROR
          - BAD_LATITUDE
          - BAD_LIMIT
          - BAD_LIMITING_MAGNITUDE
          - BAD_LONGITUDE
          - BAD_MOON_ALTITUDE
          - BAD_MOTION
          - BAD_NELM
          - BAD_NODE_MODEL
          - BAD_PAIR
          - BAD_PAIRS
          - BAD_PARAMETER_VALUE
          - BAD_PHASE_SELECTOR
          - BAD_PLACE
          - BAD_RADEC
          - BAD_RANGE
          - BAD_RANGE_VALUE
          - BAD_REFRACTION
          - BAD_SEARCH_HORIZON
          - BAD_SEXTANT_ALTITUDE
          - BAD_SIZE
          - BAD_STEP
          - BAD_TIMEZONE
          - BAD_TIME_FORMAT
          - BODY_NOT_GEOCENTRIC
          - BODY_NOT_SUPPORTED_HERE
          - BODY_REQUIRED
          - BODY_UNAVAILABLE
          - BUDGET_EXCEEDED
          - CLUSTER_PARAMETERS_REQUIRED
          - COMPUTATION_FAILED
          - COMPUTE_BUDGET_EXCEEDED
          - CONFLICTING_AYANAMSA_INPUTS
          - CONFLICTING_PARAMETERS
          - CONFLICTING_TIME_INPUTS
          - DATASET_UNAVAILABLE
          - DATE_OUT_OF_RANGE
          - ENDPOINT_BLOCKED
          - ENDPOINT_RETIRED
          - ENDPOINT_WITHDRAWN
          - EXPIRED_KEY
          - FIELD_NOT_COMPUTED
          - HOUSE_SYSTEM_UNDEFINED
          - INCOMPLETE_LOCATION
          - INCOMPLETE_RANGE
          - INTERNAL_ERROR
          - INVALID_CHARACTER
          - INVALID_KEY
          - INVALID_LOT_EXPRESSION
          - INVALID_ORB_TABLE
          - LATITUDE_AT_POLE
          - LATITUDE_TOO_EXTREME
          - LOCATION_REQUIRED
          - LONGITUDE_REQUIRED
          - METHOD_NOT_ALLOWED
          - NONEXISTENT_LOCAL_TIME
          - NOT_ACCEPTABLE
          - OBJECT_NOT_FOUND
          - OUTSIDE_MODEL_RANGE
          - PARAMETER_TOO_LONG
          - PERFECTION_BUDGET_EXCEEDED
          - PERFECTION_WINDOW_TOO_LARGE
          - PERFECTION_WINDOW_UNSUPPORTED_COMBINATION
          - PLACE_INDEX_UNAVAILABLE
          - PLACE_NOT_FOUND
          - QUERY_TOO_SHORT
          - RANGE_TOO_LARGE
          - RATE_LIMITED
          - RESPONSE_TOO_LARGE
          - REVOKED_KEY
          - SERVICE_UNAVAILABLE
          - SKY_CLASS_REQUIRED
          - STAR_POOL_TIMEOUT
          - STAR_SLOT_FAILED
          - TIMEZONE_AUTO_UNSUPPORTED
          - TIMEZONE_DATABASE_UNAVAILABLE
          - TIMEZONE_REQUIRED
          - TIME_REQUIRED
          - TIME_REQUIRED_FOR_HOUSES
          - TOO_MANY_BODIES
          - TOO_MANY_CALENDAR_SOURCES
          - TOO_MANY_DEPRESSIONS
          - TOO_MANY_PAIRS
          - TOO_MANY_PARAMETERS
          - TOO_MANY_SHOWERS
          - UNKNOWN_ASPECT
          - UNKNOWN_AYANAMSA
          - UNKNOWN_BODY
          - UNKNOWN_DERIVED
          - UNKNOWN_ENDPOINT
          - UNKNOWN_HOUSE_SYSTEM
          - UNKNOWN_LOT_TERM
          - UNKNOWN_POINT
          - UNKNOWN_SHOWER
          - URI_TOO_LONG
          description: The stable, SCREAMING_SNAKE_CASE error code a client should branch on. The full registry is at GET /v2/enums?set=error_codes.
          example: BAD_LATITUDE
        parameter:
          type:
          - string
          - 'null'
          description: The query parameter most responsible for this error, when there is one.
          example: lat
        hint:
          type:
          - string
          - 'null'
          description: A short suggestion for fixing the request.
          example: Use a signed decimal, for example lat=51.5 for north and lat=-51.5 for south. Do not append N or S
        example:
          type:
          - string
          - 'null'
          description: A worked example URL or value, when one is more useful than the hint alone.
        supported:
          type:
          - array
          - 'null'
          items: {}
          description: The accepted values for the offending parameter, when the error is about picking from a closed set.
        request_id:
          type:
          - string
          - 'null'
          description: 16 lowercase hex characters, present only on non-cacheable statuses. Quote it when reporting a 500.
          example: ba0c53d302f09df4
        error_chain:
          type:
          - array
          - 'null'
          items: {}
          description: For an error caused by resolving another parameter first (rare), the sequence of codes that led here.
        docs:
          type: string
          format: uri
          description: The API reference index.
          example: https://www.cyclecalcs.com/api/reference.html
      additionalProperties: true
    Warning:
      type: object
      description: One machine-readable notice. Exactly four keys, in this order (spec-00 11.4). Never changes the HTTP status.
      required:
      - code
      - message
      - field
      - value
      properties:
        code:
          type: string
          enum:
          - ambiguous_local_time
          - antipodal_pair_not_aspected
          - approximates_undefined_placidus
          - assumed_utc
          - birth_time_unknown
          - blocked_layer_omitted
          - cusps_not_monotonic
          - dataset_stale
          - decorative_starfield
          - dms_rounds_to_next_sign
          - dst_discontinuity
          - duplicate_alarm
          - duplicate_aspect
          - duplicate_body
          - duplicate_depression
          - duplicate_derived
          - duplicate_house_system
          - duplicate_include
          - duplicate_pair
          - duplicate_parameter
          - duplicate_point
          - duplicate_shower
          - duplicate_source
          - elevation_ignored
          - estimate_only
          - extrapolated_epoch
          - field_blocked
          - fields_ignored
          - harmonic_orb_mode_has_no_effect
          - high_latitude_caution
          - horizon_overridden
          - house_system_substituted
          - large_intercept
          - lot_term_null
          - low_altitude_precision
          - mean_node_model
          - model_disagreement
          - model_epoch_only
          - moon_dominates
          - no_astronomical_darkness
          - no_location_orientation
          - no_search_result
          - nonexistent_local_time_shifted
          - not_visible_from_location
          - oblateness_simplified
          - orbit_arc_truncated
          - parameter_ignored
          - perfection_search_truncated
          - place_ambiguous
          - place_index_tier_2
          - place_matched_by_substring
          - placement_within_error_of_boundary
          - polar_angles_flipped
          - polar_day
          - polar_night
          - polar_region
          - prose_window_differs
          - refraction_below_cutoff
          - render_degenerate
          - rounded_parameter
          - sect_tests_disagree
          - shape_ignored
          - source_window_clipped
          - station_near_window_edge
          - station_search_truncated
          - time_format_not_applicable
          - time_scale_undefined
          - timezone_from_place
          - truncated_results
          - tz_source_boundary_1970
          - tzdb_lmt_interval
          - unknown_parameter
          - unusual_navigational_body
          - vertex_undefined_at_equator
          description: A stable, lower_snake_case token. The full registry is at GET /v2/enums?set=warning_codes.
        message:
          type: string
          description: A human-readable explanation. Not parsed by machines; use `code`.
        field:
          type:
          - string
          - 'null'
          description: The data or query pointer the warning is about, dot-addressed the same way `fields` is. Null when the warning is not about one field.
        value:
          description: The value involved, when there is a single obvious one to show. Null otherwise.
  securitySchemes:
    RapidAPIKey:
      type: apiKey
      in: header
      name: X-RapidAPI-Key
      description: 'Optional, and read only by the RapidAPI gateway host (cyclecalcs-astronomy-api3.p.rapidapi.com), never by the origin in `servers`. Calling this API directly needs no key and is served at the free anonymous tier: 300 requests a minute, 2,000 an hour and 5,000 a day, counted per caller rather than globally. A key raises those limits to the subscribed tier and is what monthly volume is metered against; it is sold at https://rapidapi.com/info-8KZIhinZ9/api/cyclecalcs-astronomy-api3. It is never accepted as a query parameter, on either host.'
externalDocs:
  description: Human-readable endpoint reference
  url: https://www.cyclecalcs.com/api/reference.html