openapi: 3.1.1
info:
  title: Scalar Galaxy
  description: |
    The Scalar Galaxy is an example OpenAPI document to test OpenAPI tools and libraries. It's a fictional universe with fictional planets and fictional data.

    ## Resources

    * https://github.com/scalar/scalar
    * https://github.com/OAI/OpenAPI-Specification
    * https://scalar.com

    ## Markdown Support

    All descriptions *can* contain ~~tons of text~~ **Markdown**. [If GitHub supports the syntax](https://docs.github.com/en/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax), chances are we're supporting it, too.

    <details>
      <summary>Examples</summary>

      **Blockquotes**

      > I love OpenAPI. <3

      **Tables**

      | Feature          | Availability |
      | ---------------- | ------------ |
      | Markdown Support | ✓            |

      **Accordion**

      ```html
      <details>
        <summary>Using Details Tags</summary>
        <p>HTML Example</p>
      </details>
      ```

      **Images**

      Yes, there's support for images, too!

      ![Empty placeholder image showing the width/height](https://images.placeholders.dev/?width=1280&height=720)

      **Alerts**

      > [!tip]
      > You can use Markdown alerts in your descriptions.

    </details>
  version: 1.0.0
  contact:
    name: Scalar Support
    url: https://scalar.com
    email: support@scalar.com
  license:
    name: MIT
    url: https://opensource.org/license/MIT
externalDocs:
  description: Documentation
  url: https://github.com/scalar/scalar
servers:
  - url: https://galaxy.scalar.com
  - url: "{protocol}://void.scalar.com/{path}"
    description: Responds with your request data
    variables:
      protocol:
        enum:
          - https
          - http
        default: https
      path:
        default: ""
security:
  - bearerAuth: []
  - basicAuth: []
  - apiKeyQuery: []
  - apiKeyHeader: []
  - apiKeyHeader: []
    apiKeyQuery: []
  - apiKeyCookie: []
  - oAuth2: []
  - openIdConnect: []
x-speakeasy-webhooks:
  security:
    type: signature
    headerName: x-signature
    signatureTextEncoding: base64
    algorithm: hmac-sha256
tags:
  - name: Authentication
    description: Some endpoints are public, but some require authentication. We
      provide all the required endpoints to create an account and authorize
      yourself.
  - name: Planets
    description: Everything about planets
  - name: Celestial Bodies
    description: Celestial bodies are the planets and satellites in the Scalar Galaxy.
paths:
  /planets:
    get:
      tags:
        - Planets
      summary: Get all planets
      description: It's easy to say you know them all, but do you really? Retrieve all
        the planets and check whether you missed one.
      operationId: getAllData
      security: []
      parameters:
        - $ref: "#/components/parameters/limit"
        - $ref: "#/components/parameters/offset"
      responses:
        "200":
          description: OK
          headers:
            X-Request-ID:
              $ref: "#/components/headers/X-Request-ID"
            X-Pagination-Total:
              $ref: "#/components/headers/X-Pagination-Total"
            X-Pagination-Page:
              $ref: "#/components/headers/X-Pagination-Page"
            X-Pagination-Per-Page:
              $ref: "#/components/headers/X-Pagination-Per-Page"
            X-Cache-Control:
              $ref: "#/components/headers/X-Cache-Control"
          content:
            application/json:
              schema:
                allOf:
                  - type: object
                    properties:
                      data:
                        type: array
                        items:
                          $ref: "#/components/schemas/Planet"
                  - $ref: "#/components/schemas/PaginatedResource"
            application/xml:
              schema:
                allOf:
                  - type: object
                    xml:
                      name: planets
                    properties:
                      data:
                        type: array
                        items:
                          $ref: "#/components/schemas/Planet"
                  - $ref: "#/components/schemas/PaginatedResource"
      x-post-response: |
        pm.test("Status code is 200", () => {
          pm.response.to.have.status(200);
        });

        pm.test("Content-Type header is present", () => {
          pm.response.to.have.header("Content-Type");
        });

        pm.test("Response has data array and meta", () => {
          const jsonData = pm.response.json();
          pm.expect(jsonData).to.have.property("data");
          pm.expect(jsonData.data).to.be.an("array");
          pm.expect(jsonData).to.have.property("meta");
        });
    post:
      tags:
        - Planets
      summary: Create a planet
      description: Time to play god and create a new planet. What do you think? Ah,
        don't think too much. What could go wrong anyway?
      operationId: createPlanet
      callbacks:
        planetCreated:
          "{$request.body#/successCallbackUrl}":
            post:
              security: []
              requestBody:
                description: Information about the newly created planet
                content:
                  application/json:
                    schema:
                      $ref: "#/components/schemas/Planet"
              responses:
                "200":
                  description: Your server returns this code if it accepts the callback
                "204":
                  description: Your server should return this HTTP status code if no longer
                    interested in further updates
        planetCreationFailed:
          "{$request.body#/failureCallbackUrl}":
            post:
              security: []
              requestBody:
                description: Information about which fields failed to validate
                content:
                  application/json:
                    schema:
                      $ref: "#/components/schemas/Planet"
              responses:
                "200":
                  description: Your server returns this code if it accepts the failure callback
                    notification
        planetExploded:
          "{$request.body#/successCallbackUrl}":
            post:
              security: []
              requestBody:
                description: Information about the newly exploded planet
                content:
                  application/json:
                    schema:
                      $ref: "#/components/schemas/Planet"
              responses:
                "200":
                  description: Your server returns this code if it accepts the planet explosion
                    callback notification
      requestBody:
        description: Planet
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/Planet"
          application/xml:
            schema:
              $ref: "#/components/schemas/Planet"
      responses:
        "201":
          description: Created
          headers:
            X-Request-ID:
              $ref: "#/components/headers/X-Request-ID"
            Location:
              $ref: "#/components/headers/Location"
            X-Processing-Time:
              $ref: "#/components/headers/X-Processing-Time"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Planet"
            application/xml:
              schema:
                $ref: "#/components/schemas/Planet"
        "400":
          $ref: "#/components/responses/BadRequest"
        "403":
          $ref: "#/components/responses/Forbidden"
      x-post-response: |
        pm.test("Status code is 201", () => {
          pm.response.to.have.status(201);
        });

        pm.test("Content-Type header is present", () => {
          pm.response.to.have.header("Content-Type");
        });

        pm.test("Response is a planet with id and name", () => {
          const jsonData = pm.response.json();
          pm.expect(jsonData).to.have.property("id");
          pm.expect(jsonData).to.have.property("name");
        });
  /planets/{planetId}:
    get:
      tags:
        - Planets
      summary: Get a planet
      description: You'll better learn a little bit more about the planets. It might
        come in handy once space travel is available for everyone.
      operationId: getPlanet
      security: []
      parameters:
        - $ref: "#/components/parameters/planetId"
      responses:
        "200":
          description: Planet Found
          headers:
            X-Request-ID:
              $ref: "#/components/headers/X-Request-ID"
            ETag:
              $ref: "#/components/headers/ETag"
            Last-Modified:
              $ref: "#/components/headers/Last-Modified"
            X-Cache-Control:
              $ref: "#/components/headers/X-Cache-Control"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Planet"
            application/xml:
              schema:
                $ref: "#/components/schemas/Planet"
        "404":
          $ref: "#/components/responses/NotFound"
      x-post-response: |
        pm.test("Status code is 200", () => {
          pm.response.to.have.status(200);
        });

        pm.test("Content-Type header is present", () => {
          pm.response.to.have.header("Content-Type");
        });

        pm.test("Response is a planet with id and name", () => {
          const jsonData = pm.response.json();
          pm.expect(jsonData).to.have.property("id");
          pm.expect(jsonData).to.have.property("name");
        });
    put:
      tags:
        - Planets
      summary: Update a planet
      description: Sometimes you make mistakes, that's fine. No worries, you can
        update all planets.
      operationId: updatePlanet
      requestBody:
        description: New information about the planet
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/Planet"
          application/xml:
            schema:
              $ref: "#/components/schemas/Planet"
      parameters:
        - $ref: "#/components/parameters/planetId"
      responses:
        "200":
          description: Planet updated successfully
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Planet"
            application/xml:
              schema:
                $ref: "#/components/schemas/Planet"
        "400":
          $ref: "#/components/responses/BadRequest"
        "403":
          $ref: "#/components/responses/Forbidden"
        "404":
          $ref: "#/components/responses/NotFound"
      x-post-response: |
        pm.test("Status code is 200", () => {
          pm.response.to.have.status(200);
        });

        pm.test("Content-Type header is present", () => {
          pm.response.to.have.header("Content-Type");
        });

        pm.test("Response is a planet with id and name", () => {
          const jsonData = pm.response.json();
          pm.expect(jsonData).to.have.property("id");
          pm.expect(jsonData).to.have.property("name");
        });
    delete:
      tags:
        - Planets
      summary: Delete a planet
      operationId: deletePlanet
      description: This endpoint was used to delete planets. Unfortunately, that
        caused a lot of trouble for planets with life. So, this endpoint is now
        deprecated and should not be used anymore.
      x-scalar-stability: experimental
      parameters:
        - $ref: "#/components/parameters/planetId"
      responses:
        "204":
          description: No Content
        "404":
          $ref: "#/components/responses/NotFound"
      x-post-response: |
        pm.test("Status code is 204", () => {
          pm.response.to.have.status(204);
        });
  /planets/{planetId}/image:
    post:
      tags:
        - Planets
      summary: Upload an image to a planet
      description: Got a crazy good photo of a planet? Share it with the world!
      operationId: uploadImage
      parameters:
        - $ref: "#/components/parameters/planetId"
      requestBody:
        description: Image to upload
        content:
          multipart/form-data:
            schema:
              type: object
              properties:
                image:
                  type: string
                  format: binary
                  description: The image file to upload
                  examples:
                    - "@mars.jpg"
                    - "@jupiter.png"
      responses:
        "200":
          $ref: "#/components/responses/ImageUploaded"
        "400":
          $ref: "#/components/responses/BadRequest"
        "403":
          $ref: "#/components/responses/Forbidden"
        "404":
          $ref: "#/components/responses/NotFound"
      x-post-response: |
        pm.test("Status code is 200", () => {
          pm.response.to.have.status(200);
        });

        pm.test("Content-Type header is present", () => {
          pm.response.to.have.header("Content-Type");
        });

        pm.test("Response has message and imageUrl", () => {
          const jsonData = pm.response.json();
          pm.expect(jsonData).to.have.property("message");
          pm.expect(jsonData).to.have.property("imageUrl");
        });
  /celestial-bodies:
    post:
      tags:
        - Celestial Bodies
      summary: Create a celestial body
      operationId: createCelestialBody
      requestBody:
        description: Celestial body to create
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CelestialBody"
      responses:
        "201":
          description: Celestial body created
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CelestialBody"
      x-post-response: |
        pm.test("Status code is 201", () => {
          pm.response.to.have.status(201);
        });

        pm.test("Content-Type header is present", () => {
          pm.response.to.have.header("Content-Type");
        });

        pm.test("Response is a celestial body with id and name", () => {
          const jsonData = pm.response.json();
          pm.expect(jsonData).to.have.property("id");
          pm.expect(jsonData).to.have.property("name");
        });
  /user/signup:
    post:
      tags:
        - Authentication
      summary: Create a user
      description: Time to create a user account, eh?
      operationId: createUser
      security: []
      requestBody:
        description: User to create
        content:
          application/json:
            schema:
              allOf:
                - $ref: "#/components/schemas/User"
                - $ref: "#/components/schemas/Credentials"
            examples:
              Marc:
                value:
                  name: Marc
                  email: marc@scalar.com
                  password: i-love-scalar
              Cam:
                value:
                  name: Cam
                  email: cam@scalar.com
                  password: scalar-is-cool
              Hans:
                value:
                  name: Hans
                  email: hans@scalar.com
                  password: 5c4l4r
          application/xml:
            schema:
              allOf:
                - $ref: "#/components/schemas/User"
                - $ref: "#/components/schemas/Credentials"
            examples:
              Marc:
                value:
                  name: Marc
                  email: marc@scalar.com
                  password: i-love-scalar
              Cam:
                value:
                  name: Cam
                  email: cam@scalar.com
                  password: scalar-is-cool
              Hans:
                value:
                  name: Hans
                  email: hans@scalar.com
                  password: 5c4l4r
      responses:
        "201":
          description: User account created successfully
          headers:
            X-Request-ID:
              $ref: "#/components/headers/X-Request-ID"
            Location:
              $ref: "#/components/headers/Location"
            X-Processing-Time:
              $ref: "#/components/headers/X-Processing-Time"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/User"
            application/xml:
              schema:
                $ref: "#/components/schemas/User"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
        "409":
          $ref: "#/components/responses/Conflict"
        "422":
          $ref: "#/components/responses/UnprocessableEntity"
      x-post-response: |
        pm.test("Status code is 201", () => {
          pm.response.to.have.status(201);
        });

        pm.test("Content-Type header is present", () => {
          pm.response.to.have.header("Content-Type");
        });

        pm.test("Response is a user with id and name", () => {
          const jsonData = pm.response.json();
          pm.expect(jsonData).to.have.property("id");
          pm.expect(jsonData).to.have.property("name");
        });
  /auth/token:
    post:
      tags:
        - Authentication
      summary: Get a token
      description: Yeah, this is the boring security stuff. Just get your super secret
        token and move on.
      operationId: getToken
      security: []
      requestBody:
        description: Body for credentials to authenticate a user
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/Credentials"
          application/xml:
            schema:
              $ref: "#/components/schemas/Credentials"
      responses:
        "201":
          description: Token Created
          headers:
            X-Request-ID:
              $ref: "#/components/headers/X-Request-ID"
            X-RateLimit-Limit:
              $ref: "#/components/headers/X-RateLimit-Limit"
            X-RateLimit-Remaining:
              $ref: "#/components/headers/X-RateLimit-Remaining"
            X-RateLimit-Reset:
              $ref: "#/components/headers/X-RateLimit-Reset"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Token"
            application/xml:
              schema:
                $ref: "#/components/schemas/Token"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
        "429":
          $ref: "#/components/responses/TooManyRequests"
      x-post-response: |
        pm.test("Status code is 201", () => {
          pm.response.to.have.status(201);
        });

        pm.test("Content-Type header is present", () => {
          pm.response.to.have.header("Content-Type");
        });

        pm.test("Response contains token", () => {
          const jsonData = pm.response.json();
          pm.expect(jsonData).to.have.property("token");
          pm.expect(jsonData.token).to.be.an("string");
        });
  /me:
    get:
      tags:
        - Authentication
      summary: Get authenticated user
      description: Find yourself they say. That's what you can do here.
      operationId: getMe
      security:
        - basicAuth: []
        - oAuth2:
            - read:account
        - bearerAuth: []
        - apiKeyHeader: []
        - apiKeyQuery: []
        - apiKeyHeader: []
          apiKeyQuery: []
      responses:
        "200":
          description: Authenticated user information retrieved successfully
          headers:
            X-Request-ID:
              $ref: "#/components/headers/X-Request-ID"
            ETag:
              $ref: "#/components/headers/ETag"
            Last-Modified:
              $ref: "#/components/headers/Last-Modified"
            X-Cache-Control:
              $ref: "#/components/headers/X-Cache-Control"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/User"
            application/xml:
              schema:
                $ref: "#/components/schemas/User"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
      x-post-response: |
        pm.test("Status code is 200", () => {
          pm.response.to.have.status(200);
        });

        pm.test("Content-Type header is present", () => {
          pm.response.to.have.header("Content-Type");
        });

        pm.test("Response is a user with id and name", () => {
          const jsonData = pm.response.json();
          pm.expect(jsonData).to.have.property("id");
          pm.expect(jsonData).to.have.property("name");
        });
webhooks:
  newPlanet:
    post:
      tags:
        - Planets
      security: []
      requestBody:
        description: Information about a new planet
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/Planet"
      responses:
        "200":
          description: Return a 200 status to indicate that the data was received
            successfully
      x-post-response: |
        pm.test("Status code is 200", () => {
          pm.response.to.have.status(200);
        });
components:
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      description: JWT Bearer token authentication
    basicAuth:
      type: http
      scheme: basic
      description: Basic HTTP authentication
    apiKeyHeader:
      type: apiKey
      in: header
      name: X-API-Key
      description: API key request header
    apiKeyQuery:
      type: apiKey
      in: query
      name: api_key
      description: API key query parameter
    apiKeyCookie:
      type: apiKey
      in: cookie
      name: api_key
      description: API key browser cookie
    oAuth2:
      type: oauth2
      description: OAuth 2.0 authentication
      flows:
        authorizationCode:
          authorizationUrl: https://galaxy.scalar.com/oauth/authorize
          tokenUrl: https://galaxy.scalar.com/oauth/token
          scopes:
            read:account: read your account information
            write:planets: modify planets in your account
            read:planets: read your planets
        clientCredentials:
          tokenUrl: https://galaxy.scalar.com/oauth/token
          scopes:
            read:account: read your account information
            write:planets: modify planets in your account
            read:planets: read your planets
        implicit:
          authorizationUrl: https://galaxy.scalar.com/oauth/authorize
          scopes:
            read:account: read your account information
            write:planets: modify planets in your account
            read:planets: read your planets
        password:
          tokenUrl: https://galaxy.scalar.com/oauth/token
          scopes:
            read:account: read your account information
            write:planets: modify planets in your account
            read:planets: read your planets
    openIdConnect:
      type: openIdConnect
      openIdConnectUrl: https://galaxy.scalar.com/.well-known/openid-configuration
      description: OpenID Connect Authentication
  parameters:
    planetId:
      name: planetId
      description: The ID of the planet to get
      in: path
      required: true
      schema:
        type: integer
        format: int64
        examples:
          - 1
    limit:
      name: limit
      description: The number of items to return
      in: query
      required: false
      schema:
        type: integer
        format: int64
        default: 10
    offset:
      name: offset
      description: The number of items to skip before starting to collect the result set
      in: query
      required: false
      schema:
        type: integer
        format: int64
        default: 0
  headers:
    X-RateLimit-Limit:
      description: The number of allowed requests in the current period
      schema:
        type: integer
        example: 100
    X-RateLimit-Remaining:
      description: The number of remaining requests in the current period
      schema:
        type: integer
        example: 95
    X-RateLimit-Reset:
      description: The number of seconds left in the current period
      schema:
        type: integer
        example: 3600
    X-Request-ID:
      description: Unique identifier for the request
      schema:
        type: string
        format: uuid
        example: 123e4567-e89b-12d3-a456-426614174000
    X-Pagination-Total:
      description: Total number of items available
      schema:
        type: integer
        example: 1000
    X-Pagination-Page:
      description: Current page number
      schema:
        type: integer
        example: 1
    X-Pagination-Per-Page:
      description: Number of items per page
      schema:
        type: integer
        example: 10
    X-Cache-Control:
      description: Cache control directives
      schema:
        type: string
        example: max-age=3600, public
    ETag:
      description: Entity tag for caching
      schema:
        type: string
        example: '"33a64df551"'
    Last-Modified:
      description: The last modification date of the resource
      schema:
        type: string
        format: date-time
        example: 2023-12-01T12:00:00Z
    Location:
      description: The URL of the newly created resource
      schema:
        type: string
        format: uri
        example: https://galaxy.scalar.com/planets/123
    X-Processing-Time:
      description: The time taken to process the request in milliseconds
      schema:
        type: integer
        example: 150
  responses:
    ImageUploaded:
      description: Image uploaded
      headers:
        X-Request-ID:
          $ref: "#/components/headers/X-Request-ID"
        X-Cache-Control:
          $ref: "#/components/headers/X-Cache-Control"
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/ImageUploadedMessage"
        application/xml:
          schema:
            $ref: "#/components/schemas/ImageUploadedMessage"
    BadRequest:
      description: Bad Request
      headers:
        X-Request-ID:
          $ref: "#/components/headers/X-Request-ID"
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/BadRequestError"
        application/xml:
          schema:
            $ref: "#/components/schemas/BadRequestError"
    Forbidden:
      description: Forbidden
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/ForbiddenError"
        application/xml:
          schema:
            $ref: "#/components/schemas/ForbiddenError"
    NotFound:
      description: Not Found
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/NotFoundError"
        application/xml:
          schema:
            $ref: "#/components/schemas/NotFoundError"
    Unauthorized:
      description: Unauthorized
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/UnauthorizedError"
        application/xml:
          schema:
            $ref: "#/components/schemas/UnauthorizedError"
    Conflict:
      description: Conflict
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Conflict"
        application/xml:
          schema:
            $ref: "#/components/schemas/Conflict"
    UnprocessableEntity:
      description: Unprocessable Entity
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/UnprocessableEntity"
        application/xml:
          schema:
            $ref: "#/components/schemas/UnprocessableEntity"
    TooManyRequests:
      description: Too Many Requests
      headers:
        X-Request-ID:
          $ref: "#/components/headers/X-Request-ID"
        X-RateLimit-Limit:
          $ref: "#/components/headers/X-RateLimit-Limit"
        X-RateLimit-Remaining:
          $ref: "#/components/headers/X-RateLimit-Remaining"
        X-RateLimit-Reset:
          $ref: "#/components/headers/X-RateLimit-Reset"
        Retry-After:
          description: The number of seconds to wait before retrying
          schema:
            type: integer
            example: 60
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/TooManyRequestsError"
        application/xml:
          schema:
            $ref: "#/components/schemas/TooManyRequestsError"
  schemas:
    User:
      description: A user
      type: object
      xml:
        name: user
      properties:
        id:
          type: integer
          format: int64
          readOnly: true
          examples:
            - 1
        name:
          type: string
          examples:
            - Marc
            - Cam
            - Hans
    Credentials:
      description: Credentials to authenticate a user
      type: object
      required:
        - email
        - password
      properties:
        email:
          type: string
          format: email
          examples:
            - marc@scalar.com
            - cam@scalar.com
            - hans@scalar.com
        password:
          type: string
          writeOnly: true
          examples:
            - i-love-scalar
            - i-love-oss
            - qwerty123
    Token:
      description: A token to authenticate a user
      type: object
      properties:
        token:
          type: string
          examples:
            - eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
    CelestialBody:
      oneOf:
        - $ref: "#/components/schemas/Planet"
        - $ref: "#/components/schemas/Satellite"
      discriminator:
        propertyName: type
        mapping:
          terrestrial: "#/components/schemas/Planet"
          gas_giant: "#/components/schemas/Planet"
          ice_giant: "#/components/schemas/Planet"
          dwarf: "#/components/schemas/Planet"
          super_earth: "#/components/schemas/Planet"
          moon: "#/components/schemas/Satellite"
          asteroid: "#/components/schemas/Satellite"
          comet: "#/components/schemas/Satellite"
      description: A celestial body which can be either a planet or a satellite
    Planet:
      description: A planet in the Scalar Galaxy
      type: object
      required:
        - id
        - name
      additionalProperties: false
      xml:
        name: planet
      properties:
        id:
          type: integer
          format: int64
          readOnly: true
          examples:
            - 1
          x-variable: planetId
        name:
          type: string
          examples:
            - Mars
            - Jupiter
            - HD 40307g
        description:
          type:
            - string
            - "null"
          examples:
            - The red planet
            - A gas giant with a great red spot
        type:
          type: string
          enum:
            - terrestrial
            - gas_giant
            - ice_giant
            - dwarf
            - super_earth
          x-enum-varnames:
            - Terrestrial
            - GasGiant
            - IceGiant
            - Dwarf
            - SuperEarth
          x-enum-descriptions:
            terrestrial: Rocky planets with solid surfaces, like Earth and Mars
            gas_giant: Large planets composed mainly of hydrogen and helium, like Jupiter
              and Saturn
            ice_giant: Planets composed of water, ammonia, and methane ices, like Uranus and
              Neptune
            dwarf: Small planetary bodies that don't meet full planet criteria, like Pluto
            super_earth: Rocky planets larger than Earth but smaller than gas giants
          examples:
            - terrestrial
        habitabilityIndex:
          type: number
          format: float
          minimum: 0
          maximum: 1
          description: A score from 0 to 1 indicating potential habitability
          examples:
            - 0.68
        physicalProperties:
          type: object
          additionalProperties:
            x-additionalPropertiesName: measurement
            type: number
            format: float
            description: Additional physical measurements for the planet
          properties:
            mass:
              type: number
              format: float
              exclusiveMinimum: 0
              description: Mass in Earth masses (must be greater than 0)
              examples:
                - 0.107
            radius:
              type: number
              format: float
              exclusiveMinimum: 0
              description: Radius in Earth radii (must be greater than 0)
              examples:
                - 0.532
            gravity:
              type: number
              format: float
              description: Surface gravity in Earth g
              examples:
                - 0.378
            temperature:
              type: object
              additionalProperties:
                x-additionalPropertiesName: temperatureMetric
                type: number
                format: float
                description: Additional temperature-related measurements in Kelvin
              properties:
                min:
                  type: number
                  format: float
                  description: Minimum temperature in Kelvin
                  examples:
                    - 130
                max:
                  type: number
                  format: float
                  description: Maximum temperature in Kelvin
                  examples:
                    - 308
                average:
                  type: number
                  format: float
                  description: Average temperature in Kelvin
                  examples:
                    - 210
        atmosphere:
          type: array
          description: Atmospheric composition
          items:
            type: object
            additionalProperties:
              x-additionalPropertiesName: atmosphericData
              type: string
              description: Additional atmospheric composition data
            properties:
              compound:
                type: string
                examples:
                  - CO2
                  - N2
              percentage:
                type: number
                format: float
                exclusiveMaximum: 100
                examples:
                  - 95.3
        discoveredAt:
          type: string
          format: date-time
          examples:
            - 1610-01-07T00:00:00Z
        image:
          type:
            - string
            - "null"
          examples:
            - https://cdn.scalar.com/photos/mars.jpg
        satellites:
          type: array
          items:
            $ref: "#/components/schemas/Satellite"
        creator:
          $ref: "#/components/schemas/User"
        tags:
          type: array
          items:
            type: string
          examples:
            - - solar-system
              - rocky
              - explored
        lastUpdated:
          type: string
          format: date-time
          readOnly: true
          examples:
            - 2024-01-15T14:30:00Z
        successCallbackUrl:
          type: string
          format: uri
          description: URL which gets invoked upon a successful operation
          examples:
            - https://example.com/webhook
        failureCallbackUrl:
          type: string
          format: uri
          description: URL which gets invoked upon a failed operation
          examples:
            - https://example.com/webhook
    Satellite:
      description: Every satellite in the Scalar Galaxy
      type: object
      required:
        - name
      properties:
        id:
          type: integer
          format: int64
          readOnly: true
          examples:
            - 1
        name:
          type: string
          examples:
            - Phobos
        description:
          type:
            - string
            - "null"
          examples:
            - Phobos is the larger and innermost of the two moons of Mars.
        diameter:
          type: number
          format: float
          description: Diameter in kilometers
          examples:
            - 22.2
        type:
          type: string
          enum:
            - moon
            - asteroid
            - comet
          x-enum-varnames:
            - Moon
            - Asteroid
            - Comet
          x-enum-descriptions:
            moon: Natural satellites that orbit planets
            asteroid: Rocky objects that orbit the sun, typically found in the asteroid belt
            comet: Icy bodies that release gas when approaching the sun, creating visible
              tails
          examples:
            - moon
        orbit:
          type: object
          properties:
            planet:
              $ref: "#/components/schemas/Planet"
            orbitalPeriod:
              type: number
              format: float
              description: Orbital period in Earth days
              examples:
                - 0.319
            distance:
              type: number
              format: float
              description: Average distance from the planet in kilometers
              examples:
                - 9376
    PaginatedResource:
      description: A paginated resource
      type: object
      properties:
        meta:
          type: object
          properties:
            limit:
              type: integer
              format: int64
              examples:
                - 10
            offset:
              type: integer
              format: int64
              examples:
                - 0
            total:
              type: integer
              format: int64
              examples:
                - 100
            next:
              type:
                - string
                - "null"
              examples:
                - /planets?limit=10&offset=10
    ImageUploadedMessage:
      x-scalar-ignore: true
      description: Message about an image upload
      type: object
      properties:
        message:
          type: string
          examples:
            - Image uploaded successfully
        imageUrl:
          type: string
          description: The URL where the uploaded image can be accessed
          examples:
            - https://cdn.scalar.com/images/8f47c132-9d1f-4f83-b5a4-91db5ee757ab.jpg
        uploadedAt:
          type: string
          format: date-time
          description: Timestamp when the image was uploaded
          examples:
            - 2024-01-15T14:30:00Z
        fileSize:
          type: integer
          description: Size of the uploaded image in bytes
          examples:
            - 1048576
        mimeType:
          type: string
          description: The content type of the uploaded image
          examples:
            - image/jpeg
            - image/png
    BadRequestError:
      x-scalar-ignore: true
      description: RFC 7807 (https://datatracker.ietf.org/doc/html/rfc7807)
      type: object
      properties:
        type:
          type: string
          examples:
            - https://example.com/errors/bad-request
        title:
          type: string
          examples:
            - Bad Request
        status:
          type: integer
          format: int64
          examples:
            - 400
        detail:
          type: string
          examples:
            - The request was invalid.
    ForbiddenError:
      x-scalar-ignore: true
      description: Error response for forbidden access (RFC 7807). Returned when the
        user does not have permission to access the requested resource.
      type: object
      properties:
        type:
          type: string
          examples:
            - https://example.com/errors/forbidden
        title:
          type: string
          examples:
            - Forbidden
        status:
          type: integer
          format: int64
          examples:
            - 403
        detail:
          type: string
          examples:
            - You are not authorized to access this resource.
    NotFoundError:
      x-scalar-ignore: true
      description: Error response for resource not found (RFC 7807). Returned when the
        requested resource does not exist.
      type: object
      properties:
        type:
          type: string
          examples:
            - https://example.com/errors/not-found
        title:
          type: string
          examples:
            - Not Found
        status:
          type: integer
          format: int64
          examples:
            - 404
        detail:
          type: string
          examples:
            - The resource you are trying to access does not exist.
    UnauthorizedError:
      x-scalar-ignore: true
      description: Error response for unauthorized access (RFC 7807). Returned when
        authentication is required or has failed.
      type: object
      properties:
        type:
          type: string
          examples:
            - https://example.com/errors/not-found
        title:
          type: string
          examples:
            - Unauthorized
        status:
          type: integer
          format: int64
          examples:
            - 401
        detail:
          type: string
          examples:
            - You are not authorized to access this resource.
    Conflict:
      x-scalar-ignore: true
      description: Error response for resource conflicts (RFC 7807). Returned when the
        request conflicts with the current state of the resource.
      type: object
      properties:
        type:
          type: string
          examples:
            - https://example.com/errors/conflict
        title:
          type: string
          examples:
            - Conflict
        status:
          type: integer
          format: int64
          examples:
            - 409
        detail:
          type: string
          examples:
            - The resource you are trying to access is in conflict.
    UnprocessableEntity:
      x-scalar-ignore: true
      description: Error response for unprocessable entity (RFC 7807). Returned when
        the request is well-formed but contains semantic errors.
      type: object
      properties:
        type:
          type: string
          examples:
            - https://example.com/errors/unprocessable-entity
        title:
          type: string
          examples:
            - Unprocessable Entity
        status:
          type: integer
          format: int64
          examples:
            - 422
        detail:
          type: string
          examples:
            - The request was invalid.
    TooManyRequestsError:
      x-scalar-ignore: true
      description: Error response for rate limiting (RFC 7807). Returned when the
        client has exceeded the rate limit for requests.
      type: object
      properties:
        type:
          type: string
          examples:
            - https://example.com/errors/too-many-requests
        title:
          type: string
          examples:
            - Too Many Requests
        status:
          type: integer
          format: int64
          examples:
            - 429
        detail:
          type: string
          examples:
            - Rate limit exceeded. Please try again later.
