# Generated from typespec/ by tools/build_openapi.py. Do not edit.
openapi: 3.1.0
info:
  title: AstroCollab API
  version: 0.2.0-draft.1
  license:
    name: MIT
    identifier: MIT
  description: 'Draft API for collaborative astrophotography. A telescope''s software signs in, describes

    the rig, asks what to shoot tonight and reports what it captured. This version adopts the

    protocol Starfront already speaks. See spec/protocol.md for the rules behind each route.'
tags:
- name: discovery
- name: signin
- name: telescopes
- name: telescope
paths:
  /api/v1/agent/hello:
    post:
      operationId: hello
      summary: Say hello and describe the rig
      description: 'Says what this telescope is and, if it likes, where it points. Also a heartbeat. Send
        it

        before asking for work and whenever the rig changes.'
      parameters: []
      responses:
        '200':
          description: Success.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HelloResponse'
              examples:
                example:
                  value:
                    agent: '000000000001'
                    name: Vega 530
                    protocol: 1
                    serverTime: 1791171023.0
        '401':
          description: Missing, unknown or revoked token.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorBody'
        '409':
          description: Conflicts with how things stand, such as a rig that cannot meet a project.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorBody'
        '422':
          description: The body does not match its type.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ValidationErrorBody'
      tags:
      - telescope
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/HelloRequest'
            examples:
              example:
                value:
                  protocol: 1
                  profile:
                    name: Vega 530
                    focalLength: 530.0
                    pixelSize: 3.76
                    sensorWidth: 6248
                    sensorHeight: 4176
                    binning: 1
                    filters:
                      Ha: 7.0
                      OIII: 7.0
                      SII: 7.0
                      L: null
                    colour: false
                    rotation: null
                    typicalHfr: 2.4
                    typicalGuideRms: 0.62
                    exposures:
                      Ha: 300.0
                      OIII: 300.0
                      SII: 300.0
                      L: 120.0
                    hoursPerNight: 6.0
                    windowFrom: '21:30'
                    windowTo: 04:30
                    scale: 1.463313962264151
                    field:
                    - 2.53966267672956
                    - 1.6974441962264148
                  presence:
                    ra: 0.7123
                    dec: 41.27
                    state: imaging
                    target: M31 halo in narrowband
                    project: '000000000002'
                    telescope: Vega 530 narrowband
  /api/v1/agent/projects:
    get:
      operationId: openProjects
      summary: Browse open projects
      description: Every open project, and whether this telescope can help each one.
      parameters: []
      responses:
        '200':
          description: Success.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/OpenProjects'
              examples:
                example:
                  value:
                    projects:
                    - id: '000000000003'
                      name: M51 in LRGB
                      coordinator: coordinator
                      ownerId: ''
                      region:
                        ra: 202.4696
                        dec: 47.1952
                        width: 0.25
                        height: 0.2
                        rotation: 0.0
                      kind: single
                      requirements:
                        minFocalLength: null
                        maxFocalLength: 400.0
                        minScale: null
                        maxScale: null
                        acceptColour: true
                        colourMaxMoon: null
                        maxHfr: 3.0
                        maxGuideRms: null
                        minExposure: null
                        maxExposure: null
                        filters:
                          L: null
                          R: null
                          G: null
                          B: null
                        maxMoonIllumination: null
                        minMoonSeparation: null
                        minAltitude: null
                        requireCalibrated: false
                        minFramesPerVisit: 10
                      goals:
                        L: 20.0
                        R: 5.0
                        G: 5.0
                        B: 5.0
                      notes: ''
                      compatibility:
                        ok: false
                        certain: false
                        checks:
                        - check: focal length
                          ok: false
                          detail: 530 mm is longer than the 400 mm the project wants
                        - check: scale
                          ok: true
                          detail: 1.46"/px
                        - check: filters
                          ok: false
                          detail: can shoot L — but no R; no G; no B
                        - check: stars
                          ok: true
                          detail: usually 2.40", project wants 3" or better
                        summary: 'cannot contribute: 530 mm is longer than the 400 mm the project wants;
                          can shoot L — but no R; no G; no B'
                      joined: false
                      collected: {}
                      progress:
                        L:
                          goalHours: 20.0
                          atGoal: 0.0
                          average: 0.0
                          thinnest: 0.0
                        R:
                          goalHours: 5.0
                          atGoal: 0.0
                          average: 0.0
                          thinnest: 0.0
                        G:
                          goalHours: 5.0
                          atGoal: 0.0
                          average: 0.0
                          thinnest: 0.0
                        B:
                          goalHours: 5.0
                          atGoal: 0.0
                          average: 0.0
                          thinnest: 0.0
                      participants: 0
                      participantsOnline: 0
                      participantNames: []
                    - id: '000000000002'
                      name: M31 halo in narrowband
                      coordinator: coordinator
                      ownerId: ''
                      region:
                        ra: 10.6847
                        dec: 41.269
                        width: 7.0
                        height: 4.5
                        rotation: 35.0
                      kind: mosaic
                      requirements:
                        minFocalLength: null
                        maxFocalLength: null
                        minScale: null
                        maxScale: null
                        acceptColour: true
                        colourMaxMoon: null
                        maxHfr: 3.5
                        maxGuideRms: null
                        minExposure: 120.0
                        maxExposure: 600.0
                        filters:
                          H: 7.0
                          O: 7.0
                        maxMoonIllumination: null
                        minMoonSeparation: 30.0
                        minAltitude: 30.0
                        requireCalibrated: false
                        minFramesPerVisit: 10
                      goals:
                        H: 10.0
                        O: 10.0
                      notes: Faint H-alpha and OIII around M31. Calibrated subs only.
                      compatibility:
                        ok: true
                        certain: true
                        checks:
                        - check: scale
                          ok: true
                          detail: 1.46"/px
                        - check: filters
                          ok: true
                          detail: can shoot H, O
                        - check: exposures
                          ok: true
                          detail: the default exposures suit the project
                        - check: stars
                          ok: true
                          detail: usually 2.40", project wants 3.5" or better
                        summary: can contribute
                      joined: false
                      collected: {}
                      progress:
                        H:
                          goalHours: 10.0
                          atGoal: 0.0
                          average: 0.0
                          thinnest: 0.0
                        O:
                          goalHours: 10.0
                          atGoal: 0.0
                          average: 0.0
                          thinnest: 0.0
                      participants: 0
                      participantsOnline: 0
                      participantNames: []
                    protocol: 1
        '401':
          description: Missing, unknown or revoked token.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorBody'
        '422':
          description: The body does not match its type.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ValidationErrorBody'
      tags:
      - telescope
  /api/v1/agent/projects/{project_id}/depth:
    get:
      operationId: projectDepth
      summary: See a project's depth map
      description: Everybody's accepted depth on a fine grid over the region, per filter, and the progress
        it adds up to.
      parameters:
      - name: project_id
        in: path
        required: true
        schema:
          $ref: '#/components/schemas/Id'
      responses:
        '200':
          description: Success.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DepthMap'
              examples:
                example:
                  value:
                    project: '000000000002'
                    name: M31 halo in narrowband
                    region:
                      ra: 10.6847
                      dec: 41.269
                      width: 7.0
                      height: 4.5
                      rotation: 35.0
                    columns: 16
                    rows: 11
                    cells:
                    - ra: 6.4491057933185525
                      dec: 39.22354545454545
                      width: 0.4375
                      height: 0.4375
                      row: 0
                      column: 0
                    - ra: 7.013851687542745
                      dec: 39.22354545454545
                      width: 0.4375
                      height: 0.4375
                      row: 0
                      column: 1
                    - ra: 7.578597581766939
                      dec: 39.22354545454545
                      width: 0.4375
                      height: 0.4375
                      row: 0
                      column: 2
                    - ra: 8.14334347599113
                      dec: 39.22354545454545
                      width: 0.4375
                      height: 0.4375
                      row: 0
                      column: 3
                    - ra: 8.708089370215324
                      dec: 39.22354545454545
                      width: 0.4375
                      height: 0.4375
                      row: 0
                      column: 4
                    - ra: 9.272835264439518
                      dec: 39.22354545454545
                      width: 0.4375
                      height: 0.4375
                      row: 0
                      column: 5
                    - ra: 9.83758115866371
                      dec: 39.22354545454545
                      width: 0.4375
                      height: 0.4375
                      row: 0
                      column: 6
                    - ra: 10.402327052887903
                      dec: 39.22354545454545
                      width: 0.4375
                      height: 0.4375
                      row: 0
                      column: 7
                    - ra: 10.967072947112095
                      dec: 39.22354545454545
                      width: 0.4375
                      height: 0.4375
                      row: 0
                      column: 8
                    - ra: 11.531818841336289
                      dec: 39.22354545454545
                      width: 0.4375
                      height: 0.4375
                      row: 0
                      column: 9
                    - ra: 12.09656473556048
                      dec: 39.22354545454545
                      width: 0.4375
                      height: 0.4375
                      row: 0
                      column: 10
                    - ra: 12.661310629784674
                      dec: 39.22354545454545
                      width: 0.4375
                      height: 0.4375
                      row: 0
                      column: 11
                    - ra: 13.226056524008868
                      dec: 39.22354545454545
                      width: 0.4375
                      height: 0.4375
                      row: 0
                      column: 12
                    - ra: 13.79080241823306
                      dec: 39.22354545454545
                      width: 0.4375
                      height: 0.4375
                      row: 0
                      column: 13
                    - ra: 14.355548312457254
                      dec: 39.22354545454545
                      width: 0.4375
                      height: 0.4375
                      row: 0
                      column: 14
                    - ra: 14.920294206681447
                      dec: 39.22354545454545
                      width: 0.4375
                      height: 0.4375
                      row: 0
                      column: 15
                    - ra: 6.424166522727009
                      dec: 39.632636363636365
                      width: 0.4375
                      height: 0.4375
                      row: 1
                      column: 0
                    - ra: 6.992237653030074
                      dec: 39.632636363636365
                      width: 0.4375
                      height: 0.4375
                      row: 1
                      column: 1
                    - ra: 7.56030878333314
                      dec: 39.632636363636365
                      width: 0.4375
                      height: 0.4375
                      row: 1
                      column: 2
                    - ra: 8.128379913636206
                      dec: 39.632636363636365
                      width: 0.4375
                      height: 0.4375
                      row: 1
                      column: 3
                    - ra: 8.69645104393927
                      dec: 39.632636363636365
                      width: 0.4375
                      height: 0.4375
                      row: 1
                      column: 4
                    - ra: 9.264522174242336
                      dec: 39.632636363636365
                      width: 0.4375
                      height: 0.4375
                      row: 1
                      column: 5
                    - ra: 9.832593304545401
                      dec: 39.632636363636365
                      width: 0.4375
                      height: 0.4375
                      row: 1
                      column: 6
                    - ra: 10.400664434848467
                      dec: 39.632636363636365
                      width: 0.4375
                      height: 0.4375
                      row: 1
                      column: 7
                    - ra: 10.968735565151531
                      dec: 39.632636363636365
                      width: 0.4375
                      height: 0.4375
                      row: 1
                      column: 8
                    - ra: 11.536806695454597
                      dec: 39.632636363636365
                      width: 0.4375
                      height: 0.4375
                      row: 1
                      column: 9
                    - ra: 12.104877825757663
                      dec: 39.632636363636365
                      width: 0.4375
                      height: 0.4375
                      row: 1
                      column: 10
                    - ra: 12.67294895606073
                      dec: 39.632636363636365
                      width: 0.4375
                      height: 0.4375
                      row: 1
                      column: 11
                    - ra: 13.241020086363793
                      dec: 39.632636363636365
                      width: 0.4375
                      height: 0.4375
                      row: 1
                      column: 12
                    - ra: 13.80909121666686
                      dec: 39.632636363636365
                      width: 0.4375
                      height: 0.4375
                      row: 1
                      column: 13
                    - ra: 14.377162346969925
                      dec: 39.632636363636365
                      width: 0.4375
                      height: 0.4375
                      row: 1
                      column: 14
                    - ra: 14.94523347727299
                      dec: 39.632636363636365
                      width: 0.4375
                      height: 0.4375
                      row: 1
                      column: 15
                    - ra: 6.398712036600621
                      dec: 40.04172727272727
                      width: 0.4375
                      height: 0.4375
                      row: 2
                      column: 0
                    - ra: 6.970177098387204
                      dec: 40.04172727272727
                      width: 0.4375
                      height: 0.4375
                      row: 2
                      column: 1
                    - ra: 7.541642160173788
                      dec: 40.04172727272727
                      width: 0.4375
                      height: 0.4375
                      row: 2
                      column: 2
                    - ra: 8.113107221960373
                      dec: 40.04172727272727
                      width: 0.4375
                      height: 0.4375
                      row: 2
                      column: 3
                    - ra: 8.684572283746956
                      dec: 40.04172727272727
                      width: 0.4375
                      height: 0.4375
                      row: 2
                      column: 4
                    - ra: 9.25603734553354
                      dec: 40.04172727272727
                      width: 0.4375
                      height: 0.4375
                      row: 2
                      column: 5
                    - ra: 9.827502407320123
                      dec: 40.04172727272727
                      width: 0.4375
                      height: 0.4375
                      row: 2
                      column: 6
                    - ra: 10.398967469106708
                      dec: 40.04172727272727
                      width: 0.4375
                      height: 0.4375
                      row: 2
                      column: 7
                    - ra: 10.97043253089329
                      dec: 40.04172727272727
                      width: 0.4375
                      height: 0.4375
                      row: 2
                      column: 8
                    - ra: 11.541897592679875
                      dec: 40.04172727272727
                      width: 0.4375
                      height: 0.4375
                      row: 2
                      column: 9
                    - ra: 12.113362654466458
                      dec: 40.04172727272727
                      width: 0.4375
                      height: 0.4375
                      row: 2
                      column: 10
                    - ra: 12.684827716253043
                      dec: 40.04172727272727
                      width: 0.4375
                      height: 0.4375
                      row: 2
                      column: 11
                    - ra: 13.256292778039626
                      dec: 40.04172727272727
                      width: 0.4375
                      height: 0.4375
                      row: 2
                      column: 12
                    - ra: 13.82775783982621
                      dec: 40.04172727272727
                      width: 0.4375
                      height: 0.4375
                      row: 2
                      column: 13
                    - ra: 14.399222901612795
                      dec: 40.04172727272727
                      width: 0.4375
                      height: 0.4375
                      row: 2
                      column: 14
                    - ra: 14.970687963399378
                      dec: 40.04172727272727
                      width: 0.4375
                      height: 0.4375
                      row: 2
                      column: 15
                    - ra: 6.372730425850051
                      dec: 40.45081818181818
                      width: 0.4375
                      height: 0.4375
                      row: 3
                      column: 0
                    - ra: 6.947659702403378
                      dec: 40.45081818181818
                      width: 0.4375
                      height: 0.4375
                      row: 3
                      column: 1
                    - ra: 7.522588978956704
                      dec: 40.45081818181818
                      width: 0.4375
                      height: 0.4375
                      row: 3
                      column: 2
                    - ra: 8.09751825551003
                      dec: 40.45081818181818
                      width: 0.4375
                      height: 0.4375
                      row: 3
                      column: 3
                    - ra: 8.672447532063357
                      dec: 40.45081818181818
                      width: 0.4375
                      height: 0.4375
                      row: 3
                      column: 4
                    - ra: 9.247376808616684
                      dec: 40.45081818181818
                      width: 0.4375
                      height: 0.4375
                      row: 3
                      column: 5
                    - ra: 9.822306085170009
                      dec: 40.45081818181818
                      width: 0.4375
                      height: 0.4375
                      row: 3
                      column: 6
                    - ra: 10.397235361723336
                      dec: 40.45081818181818
                      width: 0.4375
                      height: 0.4375
                      row: 3
                      column: 7
                    - ra: 10.972164638276663
                      dec: 40.45081818181818
                      width: 0.4375
                      height: 0.4375
                      row: 3
                      column: 8
                    - ra: 11.54709391482999
                      dec: 40.45081818181818
                      width: 0.4375
                      height: 0.4375
                      row: 3
                      column: 9
                    - ra: 12.122023191383315
                      dec: 40.45081818181818
                      width: 0.4375
                      height: 0.4375
                      row: 3
                      column: 10
                    - ra: 12.696952467936642
                      dec: 40.45081818181818
                      width: 0.4375
                      height: 0.4375
                      row: 3
                      column: 11
                    - ra: 13.271881744489969
                      dec: 40.45081818181818
                      width: 0.4375
                      height: 0.4375
                      row: 3
                      column: 12
                    - ra: 13.846811021043294
                      dec: 40.45081818181818
                      width: 0.4375
                      height: 0.4375
                      row: 3
                      column: 13
                    - ra: 14.421740297596621
                      dec: 40.45081818181818
                      width: 0.4375
                      height: 0.4375
                      row: 3
                      column: 14
                    - ra: 14.996669574149948
                      dec: 40.45081818181818
                      width: 0.4375
                      height: 0.4375
                      row: 3
                      column: 15
                    - ra: 6.346209371995297
                      dec: 40.85990909090909
                      width: 0.4375
                      height: 0.4375
                      row: 4
                      column: 0
                    - ra: 6.924674789062591
                      dec: 40.85990909090909
                      width: 0.4375
                      height: 0.4375
                      row: 4
                      column: 1
                    - ra: 7.503140206129885
                      dec: 40.85990909090909
                      width: 0.4375
                      height: 0.4375
                      row: 4
                      column: 2
                    - ra: 8.081605623197177
                      dec: 40.85990909090909
                      width: 0.4375
                      height: 0.4375
                      row: 4
                      column: 3
                    - ra: 8.660071040264471
                      dec: 40.85990909090909
                      width: 0.4375
                      height: 0.4375
                      row: 4
                      column: 4
                    - ra: 9.238536457331765
                      dec: 40.85990909090909
                      width: 0.4375
                      height: 0.4375
                      row: 4
                      column: 5
                    - ra: 9.81700187439906
                      dec: 40.85990909090909
                      width: 0.4375
                      height: 0.4375
                      row: 4
                      column: 6
                    - ra: 10.395467291466353
                      dec: 40.85990909090909
                      width: 0.4375
                      height: 0.4375
                      row: 4
                      column: 7
                    - ra: 10.973932708533646
                      dec: 40.85990909090909
                      width: 0.4375
                      height: 0.4375
                      row: 4
                      column: 8
                    - ra: 11.55239812560094
                      dec: 40.85990909090909
                      width: 0.4375
                      height: 0.4375
                      row: 4
                      column: 9
                    - ra: 12.130863542668234
                      dec: 40.85990909090909
                      width: 0.4375
                      height: 0.4375
                      row: 4
                      column: 10
                    - ra: 12.709328959735528
                      dec: 40.85990909090909
                      width: 0.4375
                      height: 0.4375
                      row: 4
                      column: 11
                    - ra: 13.287794376802822
                      dec: 40.85990909090909
                      width: 0.4375
                      height: 0.4375
                      row: 4
                      column: 12
                    - ra: 13.866259793870114
                      dec: 40.85990909090909
                      width: 0.4375
                      height: 0.4375
                      row: 4
                      column: 13
                    - ra: 14.444725210937408
                      dec: 40.85990909090909
                      width: 0.4375
                      height: 0.4375
                      row: 4
                      column: 14
                    - ra: 15.023190628004702
                      dec: 40.85990909090909
                      width: 0.4375
                      height: 0.4375
                      row: 4
                      column: 15
                    - ra: 6.319136130169242
                      dec: 41.269
                      width: 0.4375
                      height: 0.4375
                      row: 5
                      column: 0
                    - ra: 6.901211312813343
                      dec: 41.269
                      width: 0.4375
                      height: 0.4375
                      row: 5
                      column: 1
                    - ra: 7.483286495457444
                      dec: 41.269
                      width: 0.4375
                      height: 0.4375
                      row: 5
                      column: 2
                    - ra: 8.065361678101546
                      dec: 41.269
                      width: 0.4375
                      height: 0.4375
                      row: 5
                      column: 3
                    - ra: 8.647436860745646
                      dec: 41.269
                      width: 0.4375
                      height: 0.4375
                      row: 5
                      column: 4
                    - ra: 9.229512043389747
                      dec: 41.269
                      width: 0.4375
                      height: 0.4375
                      row: 5
                      column: 5
                    - ra: 9.811587226033847
                      dec: 41.269
                      width: 0.4375
                      height: 0.4375
                      row: 5
                      column: 6
                    - ra: 10.39366240867795
                      dec: 41.269
                      width: 0.4375
                      height: 0.4375
                      row: 5
                      column: 7
                    - ra: 10.97573759132205
                      dec: 41.269
                      width: 0.4375
                      height: 0.4375
                      row: 5
                      column: 8
                    - ra: 11.557812773966152
                      dec: 41.269
                      width: 0.4375
                      height: 0.4375
                      row: 5
                      column: 9
                    - ra: 12.139887956610252
                      dec: 41.269
                      width: 0.4375
                      height: 0.4375
                      row: 5
                      column: 10
                    - ra: 12.721963139254353
                      dec: 41.269
                      width: 0.4375
                      height: 0.4375
                      row: 5
                      column: 11
                    - ra: 13.304038321898453
                      dec: 41.269
                      width: 0.4375
                      height: 0.4375
                      row: 5
                      column: 12
                    - ra: 13.886113504542555
                      dec: 41.269
                      width: 0.4375
                      height: 0.4375
                      row: 5
                      column: 13
                    - ra: 14.468188687186656
                      dec: 41.269
                      width: 0.4375
                      height: 0.4375
                      row: 5
                      column: 14
                    - ra: 15.050263869830758
                      dec: 41.269
                      width: 0.4375
                      height: 0.4375
                      row: 5
                      column: 15
                    - ra: 6.291497511254137
                      dec: 41.678090909090905
                      width: 0.4375
                      height: 0.4375
                      row: 6
                      column: 0
                    - ra: 6.87725784308692
                      dec: 41.678090909090905
                      width: 0.4375
                      height: 0.4375
                      row: 6
                      column: 1
                    - ra: 7.463018174919701
                      dec: 41.678090909090905
                      width: 0.4375
                      height: 0.4375
                      row: 6
                      column: 2
                    - ra: 8.048778506752482
                      dec: 41.678090909090905
                      width: 0.4375
                      height: 0.4375
                      row: 6
                      column: 3
                    - ra: 8.634538838585264
                      dec: 41.678090909090905
                      width: 0.4375
                      height: 0.4375
                      row: 6
                      column: 4
                    - ra: 9.220299170418045
                      dec: 41.678090909090905
                      width: 0.4375
                      height: 0.4375
                      row: 6
                      column: 5
                    - ra: 9.806059502250827
                      dec: 41.678090909090905
                      width: 0.4375
                      height: 0.4375
                      row: 6
                      column: 6
                    - ra: 10.39181983408361
                      dec: 41.678090909090905
                      width: 0.4375
                      height: 0.4375
                      row: 6
                      column: 7
                    - ra: 10.97758016591639
                      dec: 41.678090909090905
                      width: 0.4375
                      height: 0.4375
                      row: 6
                      column: 8
                    - ra: 11.563340497749172
                      dec: 41.678090909090905
                      width: 0.4375
                      height: 0.4375
                      row: 6
                      column: 9
                    - ra: 12.149100829581954
                      dec: 41.678090909090905
                      width: 0.4375
                      height: 0.4375
                      row: 6
                      column: 10
                    - ra: 12.734861161414734
                      dec: 41.678090909090905
                      width: 0.4375
                      height: 0.4375
                      row: 6
                      column: 11
                    - ra: 13.320621493247517
                      dec: 41.678090909090905
                      width: 0.4375
                      height: 0.4375
                      row: 6
                      column: 12
                    - ra: 13.906381825080299
                      dec: 41.678090909090905
                      width: 0.4375
                      height: 0.4375
                      row: 6
                      column: 13
                    - ra: 14.49214215691308
                      dec: 41.678090909090905
                      width: 0.4375
                      height: 0.4375
                      row: 6
                      column: 14
                    - ra: 15.077902488745861
                      dec: 41.678090909090905
                      width: 0.4375
                      height: 0.4375
                      row: 6
                      column: 15
                    - ra: 6.263279863099264
                      dec: 42.08718181818182
                      width: 0.4375
                      height: 0.4375
                      row: 7
                      column: 0
                    - ra: 6.852802548019362
                      dec: 42.08718181818182
                      width: 0.4375
                      height: 0.4375
                      row: 7
                      column: 1
                    - ra: 7.44232523293946
                      dec: 42.08718181818182
                      width: 0.4375
                      height: 0.4375
                      row: 7
                      column: 2
                    - ra: 8.031847917859558
                      dec: 42.08718181818182
                      width: 0.4375
                      height: 0.4375
                      row: 7
                      column: 3
                    - ra: 8.621370602779656
                      dec: 42.08718181818182
                      width: 0.4375
                      height: 0.4375
                      row: 7
                      column: 4
                    - ra: 9.210893287699754
                      dec: 42.08718181818182
                      width: 0.4375
                      height: 0.4375
                      row: 7
                      column: 5
                    - ra: 9.800415972619852
                      dec: 42.08718181818182
                      width: 0.4375
                      height: 0.4375
                      row: 7
                      column: 6
                    - ra: 10.38993865753995
                      dec: 42.08718181818182
                      width: 0.4375
                      height: 0.4375
                      row: 7
                      column: 7
                    - ra: 10.979461342460048
                      dec: 42.08718181818182
                      width: 0.4375
                      height: 0.4375
                      row: 7
                      column: 8
                    - ra: 11.568984027380147
                      dec: 42.08718181818182
                      width: 0.4375
                      height: 0.4375
                      row: 7
                      column: 9
                    - ra: 12.158506712300245
                      dec: 42.08718181818182
                      width: 0.4375
                      height: 0.4375
                      row: 7
                      column: 10
                    - ra: 12.748029397220343
                      dec: 42.08718181818182
                      width: 0.4375
                      height: 0.4375
                      row: 7
                      column: 11
                    - ra: 13.33755208214044
                      dec: 42.08718181818182
                      width: 0.4375
                      height: 0.4375
                      row: 7
                      column: 12
                    - ra: 13.927074767060539
                      dec: 42.08718181818182
                      width: 0.4375
                      height: 0.4375
                      row: 7
                      column: 13
                    - ra: 14.516597451980637
                      dec: 42.08718181818182
                      width: 0.4375
                      height: 0.4375
                      row: 7
                      column: 14
                    - ra: 15.106120136900735
                      dec: 42.08718181818182
                      width: 0.4375
                      height: 0.4375
                      row: 7
                      column: 15
                    - ra: 6.2344690507644644
                      dec: 42.496272727272725
                      width: 0.4375
                      height: 0.4375
                      row: 8
                      column: 0
                    - ra: 6.827833177329202
                      dec: 42.496272727272725
                      width: 0.4375
                      height: 0.4375
                      row: 8
                      column: 1
                    - ra: 7.4211973038939405
                      dec: 42.496272727272725
                      width: 0.4375
                      height: 0.4375
                      row: 8
                      column: 2
                    - ra: 8.014561430458679
                      dec: 42.496272727272725
                      width: 0.4375
                      height: 0.4375
                      row: 8
                      column: 3
                    - ra: 8.607925557023417
                      dec: 42.496272727272725
                      width: 0.4375
                      height: 0.4375
                      row: 8
                      column: 4
                    - ra: 9.201289683588154
                      dec: 42.496272727272725
                      width: 0.4375
                      height: 0.4375
                      row: 8
                      column: 5
                    - ra: 9.794653810152893
                      dec: 42.496272727272725
                      width: 0.4375
                      height: 0.4375
                      row: 8
                      column: 6
                    - ra: 10.388017936717631
                      dec: 42.496272727272725
                      width: 0.4375
                      height: 0.4375
                      row: 8
                      column: 7
                    - ra: 10.981382063282368
                      dec: 42.496272727272725
                      width: 0.4375
                      height: 0.4375
                      row: 8
                      column: 8
                    - ra: 11.574746189847106
                      dec: 42.496272727272725
                      width: 0.4375
                      height: 0.4375
                      row: 8
                      column: 9
                    - ra: 12.168110316411845
                      dec: 42.496272727272725
                      width: 0.4375
                      height: 0.4375
                      row: 8
                      column: 10
                    - ra: 12.761474442976581
                      dec: 42.496272727272725
                      width: 0.4375
                      height: 0.4375
                      row: 8
                      column: 11
                    - ra: 13.35483856954132
                      dec: 42.496272727272725
                      width: 0.4375
                      height: 0.4375
                      row: 8
                      column: 12
                    - ra: 13.948202696106058
                      dec: 42.496272727272725
                      width: 0.4375
                      height: 0.4375
                      row: 8
                      column: 13
                    - ra: 14.541566822670797
                      dec: 42.496272727272725
                      width: 0.4375
                      height: 0.4375
                      row: 8
                      column: 14
                    - ra: 15.134930949235535
                      dec: 42.496272727272725
                      width: 0.4375
                      height: 0.4375
                      row: 8
                      column: 15
                    - ra: 6.205050435730385
                      dec: 42.90536363636363
                      width: 0.4375
                      height: 0.4375
                      row: 9
                      column: 0
                    - ra: 6.802337044299668
                      dec: 42.90536363636363
                      width: 0.4375
                      height: 0.4375
                      row: 9
                      column: 1
                    - ra: 7.399623652868949
                      dec: 42.90536363636363
                      width: 0.4375
                      height: 0.4375
                      row: 9
                      column: 2
                    - ra: 7.996910261438231
                      dec: 42.90536363636363
                      width: 0.4375
                      height: 0.4375
                      row: 9
                      column: 3
                    - ra: 8.594196870007513
                      dec: 42.90536363636363
                      width: 0.4375
                      height: 0.4375
                      row: 9
                      column: 4
                    - ra: 9.191483478576794
                      dec: 42.90536363636363
                      width: 0.4375
                      height: 0.4375
                      row: 9
                      column: 5
                    - ra: 9.788770087146077
                      dec: 42.90536363636363
                      width: 0.4375
                      height: 0.4375
                      row: 9
                      column: 6
                    - ra: 10.386056695715359
                      dec: 42.90536363636363
                      width: 0.4375
                      height: 0.4375
                      row: 9
                      column: 7
                    - ra: 10.98334330428464
                      dec: 42.90536363636363
                      width: 0.4375
                      height: 0.4375
                      row: 9
                      column: 8
                    - ra: 11.580629912853922
                      dec: 42.90536363636363
                      width: 0.4375
                      height: 0.4375
                      row: 9
                      column: 9
                    - ra: 12.177916521423205
                      dec: 42.90536363636363
                      width: 0.4375
                      height: 0.4375
                      row: 9
                      column: 10
                    - ra: 12.775203129992486
                      dec: 42.90536363636363
                      width: 0.4375
                      height: 0.4375
                      row: 9
                      column: 11
                    - ra: 13.372489738561768
                      dec: 42.90536363636363
                      width: 0.4375
                      height: 0.4375
                      row: 9
                      column: 12
                    - ra: 13.969776347131049
                      dec: 42.90536363636363
                      width: 0.4375
                      height: 0.4375
                      row: 9
                      column: 13
                    - ra: 14.567062955700331
                      dec: 42.90536363636363
                      width: 0.4375
                      height: 0.4375
                      row: 9
                      column: 14
                    - ra: 15.164349564269614
                      dec: 42.90536363636363
                      width: 0.4375
                      height: 0.4375
                      row: 9
                      column: 15
                    - ra: 6.175008854012136
                      dec: 43.314454545454545
                      width: 0.4375
                      height: 0.4375
                      row: 10
                      column: 0
                    - ra: 6.776301006810517
                      dec: 43.314454545454545
                      width: 0.4375
                      height: 0.4375
                      row: 10
                      column: 1
                    - ra: 7.3775931596088995
                      dec: 43.314454545454545
                      width: 0.4375
                      height: 0.4375
                      row: 10
                      column: 2
                    - ra: 7.9788853124072805
                      dec: 43.314454545454545
                      width: 0.4375
                      height: 0.4375
                      row: 10
                      column: 3
                    - ra: 8.580177465205663
                      dec: 43.314454545454545
                      width: 0.4375
                      height: 0.4375
                      row: 10
                      column: 4
                    - ra: 9.181469618004044
                      dec: 43.314454545454545
                      width: 0.4375
                      height: 0.4375
                      row: 10
                      column: 5
                    - ra: 9.782761770802427
                      dec: 43.314454545454545
                      width: 0.4375
                      height: 0.4375
                      row: 10
                      column: 6
                    - ra: 10.384053923600808
                      dec: 43.314454545454545
                      width: 0.4375
                      height: 0.4375
                      row: 10
                      column: 7
                    - ra: 10.98534607639919
                      dec: 43.314454545454545
                      width: 0.4375
                      height: 0.4375
                      row: 10
                      column: 8
                    - ra: 11.586638229197572
                      dec: 43.314454545454545
                      width: 0.4375
                      height: 0.4375
                      row: 10
                      column: 9
                    - ra: 12.187930381995955
                      dec: 43.314454545454545
                      width: 0.4375
                      height: 0.4375
                      row: 10
                      column: 10
                    - ra: 12.789222534794336
                      dec: 43.314454545454545
                      width: 0.4375
                      height: 0.4375
                      row: 10
                      column: 11
                    - ra: 13.390514687592718
                      dec: 43.314454545454545
                      width: 0.4375
                      height: 0.4375
                      row: 10
                      column: 12
                    - ra: 13.9918068403911
                      dec: 43.314454545454545
                      width: 0.4375
                      height: 0.4375
                      row: 10
                      column: 13
                    - ra: 14.593098993189482
                      dec: 43.314454545454545
                      width: 0.4375
                      height: 0.4375
                      row: 10
                      column: 14
                    - ra: 15.194391145987863
                      dec: 43.314454545454545
                      width: 0.4375
                      height: 0.4375
                      row: 10
                      column: 15
                    seconds:
                      H:
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      O:
                      - 3300.0
                      - 3300.0
                      - 3300.0
                      - 3300.0
                      - 3300.0
                      - 4786.8
                      - 3300.0
                      - 3300.0
                      - 3300.0
                      - 3300.0
                      - 3010.3
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 3300.0
                      - 3300.0
                      - 3300.0
                      - 3300.0
                      - 3300.0
                      - 4838.9
                      - 3300.0
                      - 3300.0
                      - 3300.0
                      - 3300.0
                      - 2986.3
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 3300.0
                      - 3300.0
                      - 3300.0
                      - 3300.0
                      - 3300.0
                      - 4891.2
                      - 3300.0
                      - 3300.0
                      - 3300.0
                      - 3300.0
                      - 2961.7
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 3300.0
                      - 3300.0
                      - 3300.0
                      - 3300.0
                      - 3300.0
                      - 4357.9
                      - 3300.0
                      - 3300.0
                      - 3300.0
                      - 3300.0
                      - 2588.5
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                      - 0.0
                    goals:
                      H: 10.0
                      O: 10.0
                    progress:
                      H:
                        goalHours: 10.0
                        atGoal: 0.0
                        average: 0.0
                        thinnest: 0.0
                      O:
                        goalHours: 10.0
                        atGoal: 0.0
                        average: 0.024
                        thinnest: 0.0
        '401':
          description: Missing, unknown or revoked token.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorBody'
        '404':
          description: No such thing, or not this caller's.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorBody'
        '409':
          description: Conflicts with how things stand, such as a rig that cannot meet a project.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorBody'
        '422':
          description: The body does not match its type.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ValidationErrorBody'
      tags:
      - telescope
  /api/v1/agent/projects/{project_id}/join:
    post:
      operationId: joinProject
      summary: Join a project
      description: 'Takes a share of a project, checked against the profile the rig last sent. The share
        is

        the whole region tiled with this rig''s own camera, at its own sub lengths. Joining twice

        returns the share already held. Joining is consent: the share arrives accepted. Sending the

        night and the Moon deals tonight''s list at once, as `tonight` would. A rig that

        has not described its optics gets 400; one that cannot meet the rules gets 409.'
      parameters:
      - name: project_id
        in: path
        required: true
        schema:
          $ref: '#/components/schemas/Id'
      responses:
        '200':
          description: Success.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/JoinResponse'
              examples:
                example:
                  value:
                    task:
                      id: '000000000004'
                      project: '000000000002'
                      projectName: M31 halo in narrowband
                      agent: '000000000001'
                      region:
                        ra: 10.6847
                        dec: 41.269
                        width: 7.0
                        height: 4.5
                        rotation: 35.0
                      filters:
                      - filter: H
                        exposure: 300.0
                        hours: 10.0
                      - filter: O
                        exposure: 300.0
                        hours: 10.0
                      state: accepted
                      version: 2
                      issued: 1791171029.0
                      note: joined by Vega 530
                      seconds: 72000.0
                      cells:
                      - row: 0
                        column: 0
                        ra: 7.648994769812747
                        dec: 39.769
                        width: 2.53966267672956
                        height: 1.6974441962264148
                        rotation: 35.0
                      - row: 0
                        column: 1
                        ra: 10.6847
                        dec: 39.769
                        width: 2.53966267672956
                        height: 1.6974441962264148
                        rotation: 35.0
                      - row: 0
                        column: 2
                        ra: 13.720405230187254
                        dec: 39.769
                        width: 2.53966267672956
                        height: 1.6974441962264148
                        rotation: 35.0
                      - row: 1
                        column: 0
                        ra: 7.580299025898128
                        dec: 41.269
                        width: 2.53966267672956
                        height: 1.6974441962264148
                        rotation: 35.0
                      - row: 1
                        column: 1
                        ra: 10.6847
                        dec: 41.269
                        width: 2.53966267672956
                        height: 1.6974441962264148
                        rotation: 35.0
                      - row: 1
                        column: 2
                        ra: 13.789100974101872
                        dec: 41.269
                        width: 2.53966267672956
                        height: 1.6974441962264148
                        rotation: 35.0
                      - row: 2
                        column: 0
                        ra: 7.506193403991872
                        dec: 42.769
                        width: 2.53966267672956
                        height: 1.6974441962264148
                        rotation: 35.0
                      - row: 2
                        column: 1
                        ra: 10.6847
                        dec: 42.769
                        width: 2.53966267672956
                        height: 1.6974441962264148
                        rotation: 35.0
                      - row: 2
                        column: 2
                        ra: 13.863206596008128
                        dec: 42.769
                        width: 2.53966267672956
                        height: 1.6974441962264148
                        rotation: 35.0
                      share:
                      - 0
                      - 1
                      - 2
                      - 3
                      - 4
                      - 5
                      kind: mosaic
                      tiledRotation: null
                      assignedAt: 1791171030.0
                      assignedNight: '2026-10-05'
                      dealtHours: 6.0
                      visit:
                        seconds: 3300.0
                        frames:
                          O: 11
                        filter: O
                        moon: 0.036
                    requirements:
                      minFocalLength: null
                      maxFocalLength: null
                      minScale: null
                      maxScale: null
                      acceptColour: true
                      colourMaxMoon: null
                      maxHfr: 3.5
                      maxGuideRms: null
                      minExposure: 120.0
                      maxExposure: 600.0
                      filters:
                        H: 7.0
                        O: 7.0
                      maxMoonIllumination: null
                      minMoonSeparation: 30.0
                      minAltitude: 30.0
                      requireCalibrated: false
                      minFramesPerVisit: 10
        '400':
          description: The request cannot be served as asked yet, such as joining before describing the
            rig.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorBody'
        '401':
          description: Missing, unknown or revoked token.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorBody'
        '404':
          description: No such thing, or not this caller's.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorBody'
        '409':
          description: Conflicts with how things stand, such as a rig that cannot meet a project.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorBody'
              examples:
                example:
                  value:
                    detail: 'cannot contribute: 1000 mm is longer than the 400 mm the project wants; can
                      shoot L — but no R; no G; no B'
        '422':
          description: The body does not match its type.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ValidationErrorBody'
      tags:
      - telescope
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/JoinRequest'
            examples:
              example:
                value:
                  hours: 0.0
                  exposure: 0.0
                  exposures:
                    Ha: 300.0
                    OIII: 300.0
                    SII: 300.0
                    L: 120.0
                  night: '2026-10-05'
                  moon: 0.12
                  moonUp: 0.3
  /api/v1/agent/report:
    post:
      operationId: report
      summary: Report what was shot
      description: 'Hands back what was shot, one record per night, filter and panel, and hears whether
        each

        counts. Reporting the same night, filter and panel again keeps the larger figure.'
      parameters: []
      responses:
        '200':
          description: Success.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ReportResponse'
              examples:
                example:
                  value:
                    recorded:
                    - id: '000000000005'
                      accepted: true
                      duplicate: false
                      verdict:
                        accepted: true
                        reasons: []
                        unverified: []
                        summary: accepted
                    - id: '000000000006'
                      accepted: true
                      duplicate: false
                      verdict:
                        accepted: true
                        reasons: []
                        unverified: []
                        summary: accepted
        '401':
          description: Missing, unknown or revoked token.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorBody'
        '403':
          description: The caller may not do this.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorBody'
        '422':
          description: The body does not match its type.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ValidationErrorBody'
      tags:
      - telescope
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ReportRequest'
            examples:
              example:
                value:
                  contributions:
                  - project: '000000000002'
                    task: '000000000004'
                    night: '2026-10-05'
                    panel: '0'
                    filterName: OIII
                    frames: 11
                    seconds: 3300.0
                    exposure: 300.0
                    footprint:
                      ra: 7.648994769812747
                      dec: 39.769
                      width: 2.53966267672956
                      height: 1.6974441962264148
                      rotation: 35.0
                    scale: 1.463313962264151
                    focalLength: 530.0
                    colour: false
                    hfr: 2.3413023396226413
                    guideRms: 0.58
                    bandpass: 7.0
                  - project: '000000000002'
                    task: '000000000004'
                    night: '2026-10-05'
                    panel: '1'
                    filterName: OIII
                    frames: 11
                    seconds: 3300.0
                    exposure: 300.0
                    footprint:
                      ra: 10.6847
                      dec: 39.769
                      width: 2.53966267672956
                      height: 1.6974441962264148
                      rotation: 35.0
                    scale: 1.463313962264151
                    focalLength: 530.0
                    colour: false
                    hfr: 2.4876337358490566
                    guideRms: 0.58
                    bandpass: 7.0
  /api/v1/agent/task:
    get:
      operationId: tonight
      summary: Ask what to shoot tonight
      description: 'Tonight''s work: each share with tonight''s panels in `share` and tonight''s filter
        and frames

        in `visit`. A list holds for the whole night the rig names and is dealt afresh the first

        time it asks in the next one. `moon` and `moonUp` describe the rig''s own sky tonight and

        decide whether it is a narrowband night. A version the rig already has means nothing new.'
      parameters:
      - name: night
        in: query
        required: false
        description: The night the rig is in, as it names its nights, such as `2026-10-05`.
        schema:
          $ref: '#/components/schemas/NightName'
        explode: false
      - name: moon
        in: query
        required: false
        description: How much of the Moon is lit tonight, 0–1.
        schema:
          type: number
          format: double
          minimum: 0
          maximum: 1
        explode: false
      - name: moonUp
        in: query
        required: false
        description: The fraction of the dark hours the Moon is up, 0–1.
        schema:
          type: number
          format: double
          minimum: 0
          maximum: 1
        explode: false
      responses:
        '200':
          description: Success.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TaskResponse'
              examples:
                example:
                  value:
                    task:
                      id: '000000000004'
                      project: '000000000002'
                      projectName: M31 halo in narrowband
                      agent: '000000000001'
                      region:
                        ra: 10.6847
                        dec: 41.269
                        width: 7.0
                        height: 4.5
                        rotation: 35.0
                      filters:
                      - filter: H
                        exposure: 300.0
                        hours: 10.0
                      - filter: O
                        exposure: 300.0
                        hours: 10.0
                      state: accepted
                      version: 2
                      issued: 1791171029.0
                      note: joined by Vega 530
                      seconds: 72000.0
                      cells:
                      - row: 0
                        column: 0
                        ra: 7.648994769812747
                        dec: 39.769
                        width: 2.53966267672956
                        height: 1.6974441962264148
                        rotation: 35.0
                      - row: 0
                        column: 1
                        ra: 10.6847
                        dec: 39.769
                        width: 2.53966267672956
                        height: 1.6974441962264148
                        rotation: 35.0
                      - row: 0
                        column: 2
                        ra: 13.720405230187254
                        dec: 39.769
                        width: 2.53966267672956
                        height: 1.6974441962264148
                        rotation: 35.0
                      - row: 1
                        column: 0
                        ra: 7.580299025898128
                        dec: 41.269
                        width: 2.53966267672956
                        height: 1.6974441962264148
                        rotation: 35.0
                      - row: 1
                        column: 1
                        ra: 10.6847
                        dec: 41.269
                        width: 2.53966267672956
                        height: 1.6974441962264148
                        rotation: 35.0
                      - row: 1
                        column: 2
                        ra: 13.789100974101872
                        dec: 41.269
                        width: 2.53966267672956
                        height: 1.6974441962264148
                        rotation: 35.0
                      - row: 2
                        column: 0
                        ra: 7.506193403991872
                        dec: 42.769
                        width: 2.53966267672956
                        height: 1.6974441962264148
                        rotation: 35.0
                      - row: 2
                        column: 1
                        ra: 10.6847
                        dec: 42.769
                        width: 2.53966267672956
                        height: 1.6974441962264148
                        rotation: 35.0
                      - row: 2
                        column: 2
                        ra: 13.863206596008128
                        dec: 42.769
                        width: 2.53966267672956
                        height: 1.6974441962264148
                        rotation: 35.0
                      share:
                      - 0
                      - 1
                      - 2
                      - 3
                      - 4
                      - 5
                      kind: mosaic
                      tiledRotation: null
                      assignedAt: 1791171030.0
                      assignedNight: '2026-10-05'
                      dealtHours: 6.0
                      visit:
                        seconds: 3300.0
                        frames:
                          O: 11
                        filter: O
                        moon: 0.036
                    tasks:
                    - id: '000000000004'
                      project: '000000000002'
                      projectName: M31 halo in narrowband
                      agent: '000000000001'
                      region:
                        ra: 10.6847
                        dec: 41.269
                        width: 7.0
                        height: 4.5
                        rotation: 35.0
                      filters:
                      - filter: H
                        exposure: 300.0
                        hours: 10.0
                      - filter: O
                        exposure: 300.0
                        hours: 10.0
                      state: accepted
                      version: 2
                      issued: 1791171029.0
                      note: joined by Vega 530
                      seconds: 72000.0
                      cells:
                      - row: 0
                        column: 0
                        ra: 7.648994769812747
                        dec: 39.769
                        width: 2.53966267672956
                        height: 1.6974441962264148
                        rotation: 35.0
                      - row: 0
                        column: 1
                        ra: 10.6847
                        dec: 39.769
                        width: 2.53966267672956
                        height: 1.6974441962264148
                        rotation: 35.0
                      - row: 0
                        column: 2
                        ra: 13.720405230187254
                        dec: 39.769
                        width: 2.53966267672956
                        height: 1.6974441962264148
                        rotation: 35.0
                      - row: 1
                        column: 0
                        ra: 7.580299025898128
                        dec: 41.269
                        width: 2.53966267672956
                        height: 1.6974441962264148
                        rotation: 35.0
                      - row: 1
                        column: 1
                        ra: 10.6847
                        dec: 41.269
                        width: 2.53966267672956
                        height: 1.6974441962264148
                        rotation: 35.0
                      - row: 1
                        column: 2
                        ra: 13.789100974101872
                        dec: 41.269
                        width: 2.53966267672956
                        height: 1.6974441962264148
                        rotation: 35.0
                      - row: 2
                        column: 0
                        ra: 7.506193403991872
                        dec: 42.769
                        width: 2.53966267672956
                        height: 1.6974441962264148
                        rotation: 35.0
                      - row: 2
                        column: 1
                        ra: 10.6847
                        dec: 42.769
                        width: 2.53966267672956
                        height: 1.6974441962264148
                        rotation: 35.0
                      - row: 2
                        column: 2
                        ra: 13.863206596008128
                        dec: 42.769
                        width: 2.53966267672956
                        height: 1.6974441962264148
                        rotation: 35.0
                      share:
                      - 0
                      - 1
                      - 2
                      - 3
                      - 4
                      - 5
                      kind: mosaic
                      tiledRotation: null
                      assignedAt: 1791171030.0
                      assignedNight: '2026-10-05'
                      dealtHours: 6.0
                      visit:
                        seconds: 3300.0
                        frames:
                          O: 11
                        filter: O
                        moon: 0.036
                    requirementsByProject:
                      '000000000002':
                        minFocalLength: null
                        maxFocalLength: null
                        minScale: null
                        maxScale: null
                        acceptColour: true
                        colourMaxMoon: null
                        maxHfr: 3.5
                        maxGuideRms: null
                        minExposure: 120.0
                        maxExposure: 600.0
                        filters:
                          H: 7.0
                          O: 7.0
                        maxMoonIllumination: null
                        minMoonSeparation: 30.0
                        minAltitude: 30.0
                        requireCalibrated: false
                        minFramesPerVisit: 10
                    version: 2
                    protocol: 1
                    requirements:
                      minFocalLength: null
                      maxFocalLength: null
                      minScale: null
                      maxScale: null
                      acceptColour: true
                      colourMaxMoon: null
                      maxHfr: 3.5
                      maxGuideRms: null
                      minExposure: 120.0
                      maxExposure: 600.0
                      filters:
                        H: 7.0
                        O: 7.0
                      maxMoonIllumination: null
                      minMoonSeparation: 30.0
                      minAltitude: 30.0
                      requireCalibrated: false
                      minFramesPerVisit: 10
        '401':
          description: Missing, unknown or revoked token.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorBody'
              examples:
                example:
                  value:
                    detail: unknown agent token
        '422':
          description: The body does not match its type.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ValidationErrorBody'
      tags:
      - telescope
  /api/v1/agent/task/{task_id}:
    post:
      operationId: setTaskState
      summary: Accept, decline or finish a share
      description: Accept, decline or finish a share. Only needed for shares a coordinator offered.
      parameters:
      - name: task_id
        in: path
        required: true
        schema:
          $ref: '#/components/schemas/Id'
      responses:
        '200':
          description: Success.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TaskEnvelope'
              examples:
                example:
                  value:
                    task:
                      id: '000000000004'
                      project: '000000000002'
                      projectName: M31 halo in narrowband
                      agent: '000000000001'
                      region:
                        ra: 10.6847
                        dec: 41.269
                        width: 7.0
                        height: 4.5
                        rotation: 35.0
                      filters:
                      - filter: H
                        exposure: 300.0
                        hours: 10.0
                      - filter: O
                        exposure: 300.0
                        hours: 10.0
                      state: accepted
                      version: 3
                      issued: 1791171029.0
                      note: joined by Vega 530
                      seconds: 72000.0
                      cells:
                      - row: 0
                        column: 0
                        ra: 7.648994769812747
                        dec: 39.769
                        width: 2.53966267672956
                        height: 1.6974441962264148
                        rotation: 35.0
                      - row: 0
                        column: 1
                        ra: 10.6847
                        dec: 39.769
                        width: 2.53966267672956
                        height: 1.6974441962264148
                        rotation: 35.0
                      - row: 0
                        column: 2
                        ra: 13.720405230187254
                        dec: 39.769
                        width: 2.53966267672956
                        height: 1.6974441962264148
                        rotation: 35.0
                      - row: 1
                        column: 0
                        ra: 7.580299025898128
                        dec: 41.269
                        width: 2.53966267672956
                        height: 1.6974441962264148
                        rotation: 35.0
                      - row: 1
                        column: 1
                        ra: 10.6847
                        dec: 41.269
                        width: 2.53966267672956
                        height: 1.6974441962264148
                        rotation: 35.0
                      - row: 1
                        column: 2
                        ra: 13.789100974101872
                        dec: 41.269
                        width: 2.53966267672956
                        height: 1.6974441962264148
                        rotation: 35.0
                      - row: 2
                        column: 0
                        ra: 7.506193403991872
                        dec: 42.769
                        width: 2.53966267672956
                        height: 1.6974441962264148
                        rotation: 35.0
                      - row: 2
                        column: 1
                        ra: 10.6847
                        dec: 42.769
                        width: 2.53966267672956
                        height: 1.6974441962264148
                        rotation: 35.0
                      - row: 2
                        column: 2
                        ra: 13.863206596008128
                        dec: 42.769
                        width: 2.53966267672956
                        height: 1.6974441962264148
                        rotation: 35.0
                      share:
                      - 0
                      - 1
                      - 2
                      - 3
                      - 4
                      - 5
                      kind: mosaic
                      tiledRotation: null
                      assignedAt: 1791171030.0
                      assignedNight: '2026-10-05'
                      dealtHours: 6.0
                      visit:
                        seconds: 3300.0
                        frames:
                          O: 11
                        filter: O
                        moon: 0.036
        '401':
          description: Missing, unknown or revoked token.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorBody'
        '404':
          description: No such thing, or not this caller's.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorBody'
        '422':
          description: The body does not match its type.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ValidationErrorBody'
      tags:
      - telescope
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/TaskStateRequest'
            examples:
              example:
                value:
                  state: accepted
  /api/v1/agents:
    post:
      operationId: enrolTelescope
      summary: Enrol a telescope
      description: Takes a person's token. Each telescope gets its own token, shown once.
      parameters: []
      responses:
        '200':
          description: Success.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TelescopeCreated'
              examples:
                example:
                  value:
                    agent:
                      id: '000000000001'
                      name: Vega 530
                      owner: Vega Observatory
                      created: 1791171016.0
                      seen: 0.0
                      profile: {}
                      owner_id: '000000000000000042'
                      presence: {}
                    token: EXAMPLE_ONLY_TOKEN_03_xxxxxxxx
        '401':
          description: Missing, unknown or revoked token.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorBody'
        '422':
          description: The body does not match its type.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ValidationErrorBody'
        '503':
          description: Not available on this server, such as sign-in when it is not set up.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorBody'
      tags:
      - telescopes
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/EnrolRequest'
            examples:
              example:
                value:
                  name: Vega 530
    get:
      operationId: listTelescopes
      summary: List your telescopes
      description: Takes a person's token. Lists the person's own telescopes.
      parameters: []
      responses:
        '200':
          description: Success.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TelescopeList'
              examples:
                example:
                  value:
                    agents:
                    - id: '000000000001'
                      name: Vega 530
                      owner: Vega Observatory
                      created: 1791171016.0
                      seen: 1791171046.0
                      profile:
                        name: Vega 530
                        focalLength: 530.0
                        pixelSize: 3.76
                        sensorWidth: 6248
                        sensorHeight: 4176
                        binning: 1
                        filters:
                          Ha: 7.0
                          OIII: 7.0
                          SII: 7.0
                          L: null
                        colour: false
                        rotation: null
                        typicalHfr: 2.4
                        typicalGuideRms: 0.62
                        exposures:
                          Ha: 300.0
                          OIII: 300.0
                          SII: 300.0
                          L: 120.0
                        hoursPerNight: 6.0
                        windowFrom: '21:30'
                        windowTo: 04:30
                        scale: 1.463313962264151
                        field:
                        - 2.53966267672956
                        - 1.6974441962264148
                      owner_id: '000000000000000042'
                      presence:
                        ra: 0.7123
                        dec: 41.27
                        state: imaging
                        target: M31 halo in narrowband
                        project: '000000000002'
                        telescope: Vega 530 narrowband
        '401':
          description: Missing, unknown or revoked token.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorBody'
        '422':
          description: The body does not match its type.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ValidationErrorBody'
        '503':
          description: Not available on this server, such as sign-in when it is not set up.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorBody'
      tags:
      - telescopes
  /api/v1/auth:
    get:
      operationId: authStatus
      summary: Can people sign in here
      parameters: []
      responses:
        '200':
          description: Success.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AuthStatus'
              examples:
                example:
                  value:
                    discord: true
                    guild: '000000000000000001'
                    roleRequired: false
                    publicUrl: https://collab.example
      tags:
      - signin
      security:
      - {}
  /api/v1/auth/login:
    post:
      operationId: authLogin
      summary: Start signing a person in
      description: 'Starts a device sign-in. The program opens `url` in the browser and polls `authPoll`

        with `code` until the person has signed in there.'
      parameters: []
      responses:
        '200':
          description: Success.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/LoginStarted'
              examples:
                example:
                  value:
                    code: EXAMPLE_ONLY_TOKEN_01_xxxxxxxx
                    url: https://collab.example/auth/discord/start?code=EXAMPLE_ONLY_TOKEN_01_xxxxxxxx
                    expiresIn: 600.0
        '503':
          description: Not available on this server, such as sign-in when it is not set up.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorBody'
      tags:
      - signin
      security:
      - {}
  /api/v1/auth/logout:
    post:
      operationId: authLogout
      summary: Sign out
      parameters: []
      responses:
        '200':
          description: Success.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SignedOut'
              examples:
                example:
                  value:
                    signedOut: true
        '401':
          description: Missing, unknown or revoked token.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorBody'
        '422':
          description: The body does not match its type.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ValidationErrorBody'
      tags:
      - signin
  /api/v1/auth/me:
    get:
      operationId: authMe
      summary: Who is signed in
      parameters: []
      responses:
        '200':
          description: Success.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Me'
              examples:
                example:
                  value:
                    id: '000000000000000042'
                    name: Vega Observatory
                    admin: false
                    canStart: true
        '401':
          description: Missing, unknown or revoked token.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorBody'
        '422':
          description: The body does not match its type.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ValidationErrorBody'
      tags:
      - signin
  /api/v1/auth/poll:
    get:
      operationId: authPoll
      summary: Wait for the person to finish signing in
      parameters:
      - name: code
        in: query
        required: true
        schema:
          type: string
          maxLength: 64
        explode: false
      responses:
        '200':
          description: Success.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/LoginPoll'
              examples:
                example:
                  value:
                    state: done
                    token: EXAMPLE_ONLY_TOKEN_02_xxxxxxxx
                    user:
                      id: '000000000000000042'
                      name: Vega Observatory
                      avatar: ''
                      admin: false
                      canStart: true
      tags:
      - signin
      security:
      - {}
  /api/v1/health:
    get:
      operationId: health
      summary: Check the server and its protocol
      parameters: []
      responses:
        '200':
          description: Success.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Health'
              examples:
                example:
                  value:
                    ok: true
                    protocol: 1
                    time: 1791171001.0
                    version: 0.2.23
                    adminConfigured: true
                    discord: true
                    roleRequired: false
      tags:
      - discovery
      security:
      - {}
  /api/v1/pair:
    post:
      operationId: pairTelescope
      summary: Pair a telescope with a code
      description: 'The other way to get a telescope token, for servers that list the `pairing` feature.
        The

        person issues a single-use code on the server''s web pages and types it into the program.

        Takes no token. Never retry on your own: a lost reply needs a new code.'
      parameters: []
      responses:
        '200':
          description: Success.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TelescopeCreated'
              examples:
                example:
                  value:
                    agent:
                      id: 000000000009
                      name: Vega 530
                      owner: Vega Observatory
                      owner_id: '000000000000000042'
                      created: 1791171016.0
                      seen: 0.0
                      profile: {}
                      presence: {}
                    token: EXAMPLE_ONLY_TOKEN_03_xxxxxxxx
        '401':
          description: Missing, unknown or revoked token.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorBody'
        '404':
          description: No such thing, or not this caller's.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorBody'
        '422':
          description: The body does not match its type.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ValidationErrorBody'
        '429':
          description: Too many tries, such as repeated bad pairing codes.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorBody'
      tags:
      - telescopes
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PairRequest'
            examples:
              example:
                value:
                  code: EXAMPLE-ONLY-PAIRING-CODE
                  name: Vega 530
      security:
      - {}
  /api/v1/presence:
    get:
      operationId: presence
      summary: See who is on the sky
      description: Telescopes that checked in during the last day, where they point and what they do.
      parameters: []
      responses:
        '200':
          description: Success.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PresenceResponse'
              examples:
                example:
                  value:
                    telescopes:
                    - id: '000000000001'
                      name: Vega 530 narrowband
                      enrolledAs: Vega 530
                      owner: Vega Observatory
                      ownerName: Vega Observatory
                      avatar: ''
                      ra: 0.7123
                      dec: 41.27
                      state: imaging
                      target: M31 halo in narrowband
                      project: '000000000002'
                      ageSeconds: 0
                      online: true
                    online: 1
                    people: 1
                    onlineSeconds: 1500
                    serverTime: 1791171045.0
        '401':
          description: Missing, unknown or revoked token.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorBody'
        '422':
          description: The body does not match its type.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ValidationErrorBody'
      tags:
      - telescope
security:
- bearerAuth: []
components:
  schemas:
    AuthStatus:
      type: object
      required:
      - discord
      properties:
        discord:
          type: boolean
          description: True when sign-in is on. Starfront servers sign people in with Discord.
        guild:
          type: string
          description: The community people must belong to, if any.
        roleRequired:
          type: boolean
          description: Starting projects needs a role.
        publicUrl:
          type: string
      description: Whether people can sign in here.
    Cell:
      type: object
      required:
      - row
      - column
      properties:
        row:
          type: integer
          format: int32
        column:
          type: integer
          format: int32
      allOf:
      - $ref: '#/components/schemas/Region'
      description: One cell of a telescope's own tiling of a project, and where it sits in that grid.
    Compatibility:
      type: object
      required:
      - ok
      - certain
      - checks
      - summary
      properties:
        ok:
          type: boolean
        certain:
          type: boolean
          description: True when every check could be made.
        checks:
          type: array
          items:
            $ref: '#/components/schemas/CompatibilityCheck'
        summary:
          type: string
      description: Whether a rig meets a project's requirements, check by check.
    CompatibilityCheck:
      type: object
      required:
      - check
      - ok
      - detail
      properties:
        check:
          type: string
        ok:
          anyOf:
          - type: boolean
          - type: 'null'
        detail:
          type: string
      description: One check of a rig against a project. `ok` is null when it cannot be told.
    Contribution:
      type: object
      properties:
        project:
          anyOf:
          - $ref: '#/components/schemas/Id'
          - type: string
            enum:
            - ''
        task:
          anyOf:
          - $ref: '#/components/schemas/Id'
          - type: string
            enum:
            - ''
        night:
          $ref: '#/components/schemas/NightName'
        filterName:
          type: string
        panel:
          type: string
          description: Which panel of the rig's tiling, as the rig numbers them; empty for a single frame.
        frames:
          type: integer
          format: int32
          default: 0
        seconds:
          type: number
          format: double
          description: Total exposure, seconds.
          default: 0
        exposure:
          type: number
          format: double
          description: Sub length, seconds.
          default: 0
        footprint:
          anyOf:
          - $ref: '#/components/schemas/Region'
          - type: 'null'
        scale:
          anyOf:
          - type: number
            format: double
          - type: 'null'
          description: Arcseconds per pixel.
        focalLength:
          anyOf:
          - type: number
            format: double
          - type: 'null'
          description: Millimetres.
        hfr:
          anyOf:
          - type: number
            format: double
          - type: 'null'
          description: Mean star size over the night, arcseconds.
        guideRms:
          anyOf:
          - type: number
            format: double
          - type: 'null'
          description: Mean guiding error over the night, arcseconds.
        moonIllumination:
          anyOf:
          - type: number
            format: double
          - type: 'null'
          description: 0–1.
        moonSeparation:
          anyOf:
          - type: number
            format: double
          - type: 'null'
          description: Degrees.
        calibrated:
          type: boolean
          default: false
        bandpass:
          anyOf:
          - type: number
            format: double
          - type: 'null'
          description: Bandpass of the filter used, nanometres.
        colour:
          type: boolean
          default: false
      description: 'One night''s work on one filter and one panel, as measured rather than as planned.
        The

        footprint is the solved one: where the telescope really pointed.'
    DepthCell:
      type: object
      required:
      - ra
      - dec
      - width
      - height
      - row
      - column
      properties:
        ra:
          type: number
          format: double
        dec:
          type: number
          format: double
        width:
          type: number
          format: double
        height:
          type: number
          format: double
        row:
          type: integer
          format: int32
        column:
          type: integer
          format: int32
      description: One cell of a depth map's fine grid.
    DepthMap:
      type: object
      required:
      - project
      - name
      - region
      - columns
      - rows
      - cells
      - seconds
      - goals
      - progress
      properties:
        project:
          $ref: '#/components/schemas/Id'
        name:
          type: string
        region:
          $ref: '#/components/schemas/Region'
        columns:
          type: integer
          format: int32
        rows:
          type: integer
          format: int32
        cells:
          type: array
          items:
            $ref: '#/components/schemas/DepthCell'
        seconds:
          type: object
          unevaluatedProperties:
            type: array
            items:
              type: number
              format: double
          description: Per filter, seconds on each cell, in the order of `cells`.
        goals:
          type: object
          unevaluatedProperties:
            type: number
            format: double
          description: Hours wanted per filter at every point.
        progress:
          type: object
          unevaluatedProperties:
            $ref: '#/components/schemas/FilterProgress'
      description: 'A project''s depth map: the region cut into a fine north-up grid, with everybody''s
        accepted

        seconds on each cell, per filter. Each accepted record credits the cells its footprint

        covers, in proportion to how much of each it covers.'
    EnrolRequest:
      type: object
      required:
      - name
      properties:
        name:
          type: string
          minLength: 1
          maxLength: 80
          description: What the owner calls this telescope.
        owner:
          type: string
          maxLength: 80
          default: ''
    ErrorBody:
      type: object
      required:
      - detail
      properties:
        detail:
          type: string
      description: An error. `detail` says what went wrong, in words to show the operator.
    FilterProgress:
      type: object
      required:
      - goalHours
      - atGoal
      - average
      - thinnest
      properties:
        goalHours:
          type: number
          format: double
          description: Depth wanted at every point, hours.
        atGoal:
          type: number
          format: double
          description: Share of the region at the goal depth (within a tenth of it), 0–1.
        average:
          type: number
          format: double
          description: The region's depth against the goal, each point capped at the goal, 0–1.
        thinnest:
          type: number
          format: double
          description: The least-covered point's depth against the goal, 0–1.
      description: How far one filter has got across the whole region, everybody's accepted data together.
    FilterTask:
      type: object
      required:
      - filter
      - exposure
      - hours
      properties:
        filter:
          type: string
        exposure:
          type: number
          format: double
          description: Sub length, seconds.
        hours:
          type: number
          format: double
          description: Depth wanted on each panel over all nights, hours.
      description: 'One filter''s part of a share: sub length, and depth wanted on each panel.'
    Health:
      type: object
      required:
      - ok
      - protocol
      - time
      - version
      properties:
        ok:
          type: boolean
        protocol:
          type: integer
          format: int32
          description: Protocol version, an integer. This draft is protocol 1.
        time:
          $ref: '#/components/schemas/UnixTime'
        version:
          type: string
          description: The server's own build version.
        features:
          type: array
          items:
            type: string
          description: Optional parts this server offers, such as `signin`, `pairing` or `files`.
      description: Whether the server is up, which protocol it speaks, and what it offers.
    HelloRequest:
      type: object
      properties:
        protocol:
          type: integer
          format: int32
          description: The protocol the program speaks.
          default: 1
        profile:
          $ref: '#/components/schemas/RigProfile'
        presence:
          anyOf:
          - $ref: '#/components/schemas/Presence'
          - type: 'null'
          description: Where the telescope points, for the others' charts. Optional.
    HelloResponse:
      type: object
      required:
      - agent
      - name
      - protocol
      - serverTime
      properties:
        agent:
          $ref: '#/components/schemas/Id'
        name:
          type: string
        protocol:
          type: integer
          format: int32
        serverTime:
          $ref: '#/components/schemas/UnixTime'
    Id:
      type: string
      pattern: ^[0-9a-f]{12}$
      description: 'A server-made identifier: 12 lowercase hexadecimal characters.'
    JoinRequest:
      type: object
      properties:
        hours:
          type: number
          format: double
          minimum: 0
          maximum: 24
          description: Hours per filter to give, capped by the project's goal. 0 takes the goal.
          default: 0
        exposure:
          type: number
          format: double
          minimum: 0
          maximum: 3600
          description: Sub length for a filter with no entry in `exposures`. 0 takes the middle of the
            project's range.
          default: 0
        exposures:
          type: object
          unevaluatedProperties:
            type: number
            format: double
          description: The rig's own sub length per filter, seconds.
        night:
          $ref: '#/components/schemas/NightName'
          description: The night the rig is in, so the first deal is tonight's.
          default: ''
        moon:
          anyOf:
          - type: number
            format: double
          - type: 'null'
          minimum: 0
          maximum: 1
          description: How much of the Moon is lit tonight, 0–1.
        moonUp:
          anyOf:
          - type: number
            format: double
          - type: 'null'
          minimum: 0
          maximum: 1
          description: The fraction of the dark hours the Moon is up, 0–1.
    JoinResponse:
      type: object
      required:
      - task
      - requirements
      properties:
        task:
          anyOf:
          - $ref: '#/components/schemas/Task'
          - type: 'null'
        requirements:
          $ref: '#/components/schemas/Requirements'
        alreadyJoined:
          type: boolean
          description: The rig already held a share; that one is returned.
    LoginPoll:
      type: object
      required:
      - state
      properties:
        state:
          type: string
          enum:
          - pending
          - done
          - claimed
          - expired
        token:
          type: string
        user:
          $ref: '#/components/schemas/SignedInUser'
      description: '`done` hands over the person''s token, once.'
    LoginStarted:
      type: object
      required:
      - code
      - url
      - expiresIn
      properties:
        code:
          type: string
        url:
          type: string
          description: Open this in the browser.
        expiresIn:
          type: integer
          format: int32
          description: Seconds the code stays good.
      description: 'A sign-in in progress: a code for the program to hold, and a page for the person to
        open.'
    Me:
      type: object
      required:
      - id
      - name
      - admin
      - canStart
      properties:
        id:
          type: string
        name:
          type: string
        admin:
          type: boolean
        canStart:
          type: boolean
    NightName:
      type: string
      maxLength: 16
      description: A night as the rig names it, such as `2026-10-05`.
    OpenProject:
      type: object
      required:
      - id
      - name
      - coordinator
      - ownerId
      - region
      - kind
      - requirements
      - goals
      - notes
      - compatibility
      - joined
      - collected
      - participants
      - participantsOnline
      - participantNames
      properties:
        id:
          $ref: '#/components/schemas/Id'
        name:
          type: string
        coordinator:
          type: string
        ownerId:
          type: string
          description: Who started it.
        region:
          $ref: '#/components/schemas/Region'
        kind:
          type: string
          enum:
          - single
          - mosaic
          description: '`single`: one object everybody frames. `mosaic`: a region each rig tiles with
            its own camera.'
        requirements:
          $ref: '#/components/schemas/Requirements'
        goals:
          type: object
          unevaluatedProperties:
            type: number
            format: double
          description: Depth wanted at every point of the region, per filter, in hours.
        notes:
          type: string
        compatibility:
          $ref: '#/components/schemas/Compatibility'
          description: Whether this telescope can help, from the profile it last sent.
        joined:
          type: boolean
          description: This telescope already holds a share.
        collected:
          type: object
          unevaluatedProperties:
            type: number
            format: double
          description: Accepted hours so far, per filter.
        participants:
          type: integer
          format: int32
        participantsOnline:
          type: integer
          format: int32
        participantNames:
          type: array
          items:
            type: string
        progress:
          type: object
          unevaluatedProperties:
            $ref: '#/components/schemas/FilterProgress'
          description: Per filter, how far the region has got.
      description: An open project, as a telescope browsing for one sees it.
    OpenProjects:
      type: object
      required:
      - projects
      - protocol
      properties:
        projects:
          type: array
          items:
            $ref: '#/components/schemas/OpenProject'
        protocol:
          type: integer
          format: int32
    PairRequest:
      type: object
      required:
      - code
      - name
      properties:
        code:
          type: string
          minLength: 1
          maxLength: 256
          description: The single-use code the person issued.
        name:
          type: string
          minLength: 1
          maxLength: 80
          description: What to call this telescope.
      description: Trade a pairing code from the server's web pages for a telescope token.
    Presence:
      type: object
      properties:
        ra:
          anyOf:
          - type: number
            format: double
          - type: 'null'
          description: Hours.
        dec:
          anyOf:
          - type: number
            format: double
          - type: 'null'
          description: Degrees.
        state:
          type: string
          description: Such as "imaging", "slewing" or "idle".
        target:
          type: string
          description: The target's name.
        project:
          type: string
          description: The project being shot, if any.
        telescope:
          type: string
          description: What to call the telescope on the group's chart, such as its equipment profile's
            name.
      description: Where a telescope points and what it is doing, as much as it chooses to say.
    PresenceResponse:
      type: object
      required:
      - telescopes
      - online
      - people
      - onlineSeconds
      - serverTime
      properties:
        telescopes:
          type: array
          items:
            $ref: '#/components/schemas/TelescopePresence'
        online:
          type: integer
          format: int32
          description: Telescopes online now.
        people:
          type: integer
          format: int32
          description: People with a telescope online now.
        onlineSeconds:
          type: integer
          format: int32
        serverTime:
          $ref: '#/components/schemas/UnixTime'
    Recorded:
      type: object
      required:
      - id
      - accepted
      - duplicate
      - verdict
      properties:
        id:
          $ref: '#/components/schemas/Id'
        accepted:
          type: boolean
        duplicate:
          type: boolean
          description: Already reported; the larger figure stands.
        verdict:
          $ref: '#/components/schemas/Verdict'
      description: What happened to one contribution in a report.
    Region:
      type: object
      required:
      - ra
      - dec
      - width
      - height
      properties:
        ra:
          type: number
          format: double
          description: Right ascension of the centre, degrees.
        dec:
          type: number
          format: double
          description: Declination of the centre, degrees.
        width:
          type: number
          format: double
          description: Width on the sky, degrees.
        height:
          type: number
          format: double
          description: Height on the sky, degrees.
        rotation:
          type: number
          format: double
          description: The position angle cameras should shoot at, degrees, so panels stack the same way
            up.
          default: 0
      description: 'A rectangle of sky, north-up. Degrees throughout: `ra` is degrees, not hours. `width`

        and `height` are angles on the sky, not degrees of the RA coordinate.'
    ReportRequest:
      type: object
      properties:
        contributions:
          type: array
          items:
            $ref: '#/components/schemas/Contribution'
          maxItems: 200
          description: One record per night, filter and panel.
    ReportResponse:
      type: object
      required:
      - recorded
      properties:
        recorded:
          type: array
          items:
            $ref: '#/components/schemas/Recorded'
          description: In the order sent.
    Requirements:
      type: object
      properties:
        minFocalLength:
          anyOf:
          - type: number
            format: double
          - type: 'null'
          description: Millimetres.
        maxFocalLength:
          anyOf:
          - type: number
            format: double
          - type: 'null'
          description: Millimetres.
        minScale:
          anyOf:
          - type: number
            format: double
          - type: 'null'
          description: Arcseconds per pixel.
        maxScale:
          anyOf:
          - type: number
            format: double
          - type: 'null'
          description: Arcseconds per pixel.
        acceptColour:
          type: boolean
          description: Whether one-shot colour cameras may take part.
          default: true
        colourMaxMoon:
          anyOf:
          - type: number
            format: double
          - type: 'null'
          description: Moon illumination (0–1) above which a colour camera's night is refused.
        maxHfr:
          anyOf:
          - type: number
            format: double
          - type: 'null'
          description: Mean star size over a night, arcseconds.
        maxGuideRms:
          anyOf:
          - type: number
            format: double
          - type: 'null'
          description: Mean guiding error over a night, arcseconds.
        minExposure:
          anyOf:
          - type: number
            format: double
          - type: 'null'
          description: Shortest sub, seconds.
        maxExposure:
          anyOf:
          - type: number
            format: double
          - type: 'null'
          description: Longest sub, seconds.
        filters:
          type: object
          unevaluatedProperties:
            anyOf:
            - type: number
              format: double
            - type: 'null'
          description: Filters wanted, each to the widest bandpass accepted in nanometres, or null for
            any.
        maxMoonIllumination:
          anyOf:
          - type: number
            format: double
          - type: 'null'
          description: Moon illumination, 0–1.
        minMoonSeparation:
          anyOf:
          - type: number
            format: double
          - type: 'null'
          description: Degrees from the Moon.
        minAltitude:
          anyOf:
          - type: number
            format: double
          - type: 'null'
          description: Lowest altitude to shoot at, degrees.
        requireCalibrated:
          type: boolean
          description: Frames must be calibrated.
          default: false
        minFramesPerVisit:
          type: integer
          format: int32
          description: 'The fewest frames a visit to one panel is worth: a rig stacks its own frames.'
          default: 10
      description: 'What a project will take. Units mean the same on every rig: star size and guiding
        are in

        arcseconds, never pixels. Null means no limit.'
    RigProfile:
      type: object
      properties:
        name:
          type: string
        focalLength:
          anyOf:
          - type: number
            format: double
          - type: 'null'
          description: Millimetres.
        pixelSize:
          anyOf:
          - type: number
            format: double
          - type: 'null'
          description: Microns, unbinned.
        sensorWidth:
          anyOf:
          - type: integer
            format: int32
          - type: 'null'
          description: Pixels, unbinned.
        sensorHeight:
          anyOf:
          - type: integer
            format: int32
          - type: 'null'
          description: Pixels, unbinned.
        binning:
          type: integer
          format: int32
          default: 1
        filters:
          type: object
          unevaluatedProperties:
            anyOf:
            - type: number
              format: double
            - type: 'null'
          description: Filter name to bandpass in nanometres, or null where the bandpass is not known.
        colour:
          type: boolean
          description: 'A one-shot colour camera: broadband RGB, whatever is in front of it.'
          default: false
        rotation:
          anyOf:
          - type: number
            format: double
          - type: 'null'
          description: 'The camera''s position angle in degrees when nothing can turn it. Null when a
            rotator can

            set whatever angle a project asks for.'
        typicalHfr:
          anyOf:
          - type: number
            format: double
          - type: 'null'
          description: Typical star size on this rig, arcseconds.
        typicalGuideRms:
          anyOf:
          - type: number
            format: double
          - type: 'null'
          description: Typical guiding error on this rig, arcseconds.
        exposures:
          type: object
          unevaluatedProperties:
            type: number
            format: double
          description: 'The sub length this rig shoots each filter at, seconds: what its darks are built
            for.

            Work is dealt at these lengths so every frame can be calibrated.'
        hoursPerNight:
          anyOf:
          - type: number
            format: double
          - type: 'null'
          description: Hours a night the rig gives the collaboration. Null means as long as targets are
            up.
        windowFrom:
          type: string
          description: Start of the rig's window, local clock time such as "21:00".
        windowTo:
          type: string
          description: End of the rig's window, local clock time.
        scale:
          anyOf:
          - type: number
            format: double
          - type: 'null'
          description: Arcseconds per pixel, worked out by the program from the optics.
        field:
          anyOf:
          - type: array
            items:
              type: number
              format: double
          - type: 'null'
          description: Field of view, [width, height] in degrees, worked out by the program.
      description: 'What a telescope is and what it achieves, sent with every hello. Numbers the program
        does

        not know are null. The server uses this to say whether the rig can help a project and to

        cut its cells and deal its nights.'
    SignedInUser:
      type: object
      required:
      - id
      - name
      - admin
      - canStart
      properties:
        id:
          type: string
        name:
          type: string
        avatar:
          type: string
        admin:
          type: boolean
        canStart:
          type: boolean
          description: May start projects on this server.
    SignedOut:
      type: object
      required:
      - signedOut
      properties:
        signedOut:
          type: boolean
    Task:
      type: object
      required:
      - id
      - project
      - region
      properties:
        id:
          $ref: '#/components/schemas/Id'
        project:
          $ref: '#/components/schemas/Id'
        projectName:
          type: string
        agent:
          $ref: '#/components/schemas/Id'
          description: The telescope this share belongs to.
        region:
          $ref: '#/components/schemas/Region'
          description: The whole project's sky.
        filters:
          type: array
          items:
            $ref: '#/components/schemas/FilterTask'
        state:
          type: string
          enum:
          - offered
          - accepted
          - declined
          - complete
          - superseded
          description: '`accepted` once the rig has joined or accepted it. `offered` when a coordinator
            pushed it

            and nobody has accepted yet. `superseded` when replaced by a newer share of the same project.'
          default: offered
        version:
          type: integer
          format: int32
          description: Rises whenever the share changes; a rig with this version has nothing new to do.
          default: 1
        issued:
          $ref: '#/components/schemas/UnixTime'
        note:
          type: string
        seconds:
          anyOf:
          - type: number
            format: double
          - type: 'null'
          description: Total seconds the share is worth over all nights.
        cells:
          type: array
          items:
            $ref: '#/components/schemas/Cell'
          description: This telescope's tiling of the region.
        share:
          type: array
          items:
            type: integer
            format: int32
          description: Indexes into `cells` to shoot tonight, in order.
        kind:
          type: string
          enum:
          - single
          - mosaic
          default: mosaic
        visit:
          anyOf:
          - $ref: '#/components/schemas/Visit'
          - type: 'null'
        assignedNight:
          anyOf:
          - $ref: '#/components/schemas/NightName'
          - type: 'null'
          description: The night the share was dealt for.
        assignedAt:
          anyOf:
          - $ref: '#/components/schemas/UnixTime'
          - type: 'null'
        dealtHours:
          anyOf:
          - type: number
            format: double
          - type: 'null'
          description: Hours of the night the share was dealt for.
        tiledRotation:
          anyOf:
          - type: number
            format: double
          - type: 'null'
          description: The camera angle the cells were cut for.
      description: 'A telescope''s share of a project: the whole region tiled with its own camera, and
        which

        of those cells are its to shoot tonight. A change to the share bumps `version`.'
    TaskEnvelope:
      type: object
      required:
      - task
      properties:
        task:
          $ref: '#/components/schemas/Task'
    TaskResponse:
      type: object
      required:
      - task
      - tasks
      - version
      - protocol
      properties:
        task:
          anyOf:
          - $ref: '#/components/schemas/Task'
          - type: 'null'
          description: The first share, for programs that expect one.
        tasks:
          type: array
          items:
            $ref: '#/components/schemas/Task'
        requirementsByProject:
          type: object
          unevaluatedProperties:
            $ref: '#/components/schemas/Requirements'
          description: Each share's project requirements, so the program can judge its own data first.
        version:
          type: integer
          format: int32
          description: The first share's version.
        protocol:
          type: integer
          format: int32
        requirements:
          $ref: '#/components/schemas/Requirements'
          description: The first share's project requirements.
      description: Every share this telescope holds, each dealt for tonight.
    TaskStateRequest:
      type: object
      required:
      - state
      properties:
        state:
          type: string
          enum:
          - accepted
          - declined
          - complete
    Telescope:
      type: object
      required:
      - id
      - name
      - created
      properties:
        id:
          $ref: '#/components/schemas/Id'
        name:
          type: string
        owner:
          type: string
          description: The owner's display name.
        owner_id:
          type: string
        created:
          $ref: '#/components/schemas/UnixTime'
        seen:
          $ref: '#/components/schemas/UnixTime'
          description: Last check-in, or 0 if never.
        profile:
          $ref: '#/components/schemas/RigProfile'
        presence:
          anyOf:
          - $ref: '#/components/schemas/Presence'
          - type: 'null'
      description: An enrolled telescope. The token is never listed.
    TelescopeCreated:
      type: object
      required:
      - agent
      - token
      properties:
        agent:
          $ref: '#/components/schemas/Telescope'
        token:
          type: string
      description: A telescope's credential. The token is shown once; keep it on that telescope.
    TelescopeList:
      type: object
      required:
      - agents
      properties:
        agents:
          type: array
          items:
            $ref: '#/components/schemas/Telescope'
    TelescopePresence:
      type: object
      required:
      - id
      - name
      - owner
      - ra
      - dec
      - state
      - target
      - project
      - ageSeconds
      - online
      properties:
        id:
          $ref: '#/components/schemas/Id'
        name:
          type: string
          description: What the telescope says to call it, or the name it was enrolled under.
        enrolledAs:
          type: string
          description: The name it was enrolled under.
        owner:
          type: string
        ra:
          anyOf:
          - type: number
            format: double
          - type: 'null'
          description: Hours.
        dec:
          anyOf:
          - type: number
            format: double
          - type: 'null'
          description: Degrees.
        state:
          type: string
        target:
          type: string
        project:
          type: string
        ageSeconds:
          type: integer
          format: int32
          description: Seconds since it last checked in.
        online:
          type: boolean
          description: Checked in within `onlineSeconds`.
      description: One telescope as the group sees it.
    UnixTime:
      type: number
      format: double
      minimum: 0
      description: Seconds since 1970-01-01 UTC, as a number.
    ValidationErrorBody:
      type: object
      required:
      - detail
      properties:
        detail:
          type: array
          items:
            type: object
            properties:
              loc:
                type: array
                items:
                  anyOf:
                  - type: string
                  - type: integer
                    format: int32
              msg:
                type: string
              type:
                type: string
            required:
            - loc
            - msg
            - type
      description: A request body that does not match its type. Each entry names a field and the problem.
    Verdict:
      type: object
      required:
      - accepted
      properties:
        accepted:
          type: boolean
        reasons:
          type: array
          items:
            type: string
        unverified:
          type: array
          items:
            type: string
        summary:
          type: string
        overriddenBy:
          anyOf:
          - type: string
          - type: 'null'
        overrideReason:
          anyOf:
          - type: string
          - type: 'null'
      description: 'The server''s judgement of one contribution. Advisory: a project''s coordinator can
        overrule

        it. `unverified` lists rules that could not be checked because a measurement was missing.'
    Visit:
      type: object
      properties:
        seconds:
          anyOf:
          - type: number
            format: double
          - type: 'null'
          description: Seconds to spend on each panel tonight.
        frames:
          type: object
          unevaluatedProperties:
            type: integer
            format: int32
          description: Frames per filter on each panel tonight.
        filter:
          anyOf:
          - type: string
          - type: 'null'
          description: Tonight's one filter, on a mosaic.
        moon:
          anyOf:
          - type: number
            format: double
          - type: 'null'
          description: How much the Moon spoils the night the list was made for, 0–1.
      description: Tonight's slice of a share.
  securitySchemes:
    bearerAuth:
      type: http
      scheme: Bearer
      description: 'Send `Authorization: Bearer <token>`. Telescope routes take a telescope''s agent token;

        account routes take a person''s token from sign-in. The two are never interchangeable.'
servers:
- url: https://collab.example
  description: Reserved example; use the address of the server you join.
  variables: {}
