Kardinal ARO API

The Kardinal Always-on Route Optimization (ARO) v2 REST API. Create and update optimization plans, manage the resources (vehicles) and orders (stops) inside them, drive the optimization lifecycle, and retrieve the computed solution with per-resource tours, waypoint arrival times, objectives and unaffected stops. Authentication is JWT bearer, with password login, MFA/OTP, Azure and Google SSO, and a refresh-token flow. Access is provisioned by invitation per customer environment; there is no self-serve sign-up.

OpenAPI Specification

kardinal-aro-openapi-original.yml Raw ↑
openapi: 3.0.3

info:
  title: Kardinal ARO API
  version: 2.55.0
  description: This document specifies the REST API of Kardinal ARO v2.
  contact:
    url: "https://kardinal.ai/"
    email: contact@kardinal.ai

servers:
  - url: /api/v2

security:
  - access_token: []

tags:
  - name: Authenticate
    description: How to authenticate, and manage the access and refresh tokens.
  - name: Plan
    description: How to create, retrieve, update and delete plans.
  - name: Resource
    description: How to create, retrieve, update and delete resources in a plan.
  - name: Order
    description: How to create, retrieve, update and delete orders in a plan.
  - name: SimplePlan
    description: How to create a plan through the use of a simple plan.
paths:
  /public_key:
    get:
      security: []
      summary: Get the public key which can be used to check the tokens
      operationId: getPublicKey
      tags:
        - Authenticate
      responses:
        "200":
          description: The content of the public key, either in JWK or PEM format.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PublicKeyJWK"
            text/plain:
              schema:
                $ref: "#/components/schemas/PublicKeyPEM"

  /auth/password/requestToken:
    post:
      summary: Request a password token
      operationId: postRequestPasswordToken
      tags:
        - Authenticate
      security: []
      parameters:
        - $ref: "#/components/parameters/originHeader"
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/UsernameRequest"
      responses:
        "204":
          description: |
            The request has been taken into account.
            If the provided username is a valid email address which corresponds to an active user, a password token will be generated and sent by mail.
            If no active user is found, the error is silently discarded and a 204 code is returned anyway.
        "400":
          $ref: "#/components/responses/BadRequest"
        "500":
          $ref: "#/components/responses/InternalServerError"

  /auth/password/validateToken:
    post:
      summary: Check if a password token is valid
      operationId: validatePasswordToken
      tags:
        - Authenticate
      security: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/TokenRequest"
      responses:
        "204":
          description: The token has been validated.
        "400":
          $ref: "#/components/responses/BadRequest"
        "500":
          $ref: "#/components/responses/InternalServerError"

  /auth/password/reset:
    post:
      summary: Reset a password for a user
      operationId: resetPassword
      tags:
        - Authenticate
      security:
        - password_token: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/PasswordRequest"
      responses:
        "204":
          description: The password has been reset.
        "400":
          $ref: "#/components/responses/BadRequest"
        "500":
          $ref: "#/components/responses/InternalServerError"

  /auth/mfa/config:
    get:
      summary: Fetch the actor's MFA config
      operationId: getActorMFAConfig
      tags:
        - Authenticate
      responses:
        "200":
          description: The actor's MFA config.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/EnvelopedMFAConfig"
        "401":
          $ref: "#/components/responses/NotAuthenticated"
        "403":
          $ref: "#/components/responses/Forbidden"
        "500":
          $ref: "#/components/responses/InternalServerError"

  /auth/mfa/disable:
    post:
      summary: Disable an OTP type in the actor's MFA config
      operationId: disableMFAConfig
      tags:
        - Authenticate
      requestBody:
        content:
          application/json:
            schema:
              oneOf:
                - $ref: "#/components/schemas/MFAConfigRequestEmail"
                - $ref: "#/components/schemas/MFAConfigRequestSMS"
                - $ref: "#/components/schemas/MFAConfigRequestTOTP"
      responses:
        "200":
          description: The updated MFA config.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/EnvelopedMFAConfig"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/NotAuthenticated"
        "403":
          $ref: "#/components/responses/Forbidden"
        "500":
          $ref: "#/components/responses/InternalServerError"

  /auth/mfa/request:
    post:
      summary: Request the update of the actor's MFA config
      operationId: requestMFAConfigUpdate
      tags:
        - Authenticate
      requestBody:
        content:
          application/json:
            schema:
              oneOf:
                - $ref: "#/components/schemas/MFAConfigRequestEmail"
                - $ref: "#/components/schemas/MFAConfigRequestSMS"
                - $ref: "#/components/schemas/MFAConfigRequestTOTP"
      responses:
        "200":
          description: The OTP token valid for 10 minutes.
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: "#/components/schemas/EnvelopedMFARequestOTPOutput"
                  - $ref: "#/components/schemas/EnvelopedMFARequestTOTPOutput"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/NotAuthenticated"
        "403":
          $ref: "#/components/responses/Forbidden"
        "500":
          $ref: "#/components/responses/InternalServerError"

  /auth/mfa/resendOTP:
    post:
      security:
        - otp_token: []
      summary: Request a new OTP code for the MFA config update validation
      operationId: requestNewMFAOTPCode
      tags:
        - Authenticate
      requestBody:
        content:
          application/json:
            schema:
              oneOf:
                - $ref: "#/components/schemas/MFAConfigResendEmail"
                - $ref: "#/components/schemas/MFAConfigResendSMS"
      responses:
        "204":
          description: The OTP code was resent.
        "401":
          $ref: "#/components/responses/NotAuthenticated"
        "403":
          $ref: "#/components/responses/Forbidden"
        "429":
          description: Too many requests.
        "500":
          $ref: "#/components/responses/InternalServerError"

  /auth/mfa/validate:
    post:
      security:
        - otp_token: []
      summary: Validate the update of the actor's MFA config
      operationId: validateMFAConfigUpdate
      tags:
        - Authenticate
      requestBody:
        content:
          application/json:
            schema:
              oneOf:
                - $ref: "#/components/schemas/MFAConfigValidationEmail"
                - $ref: "#/components/schemas/MFAConfigValidationSMS"
                - $ref: "#/components/schemas/MFAConfigValidationTOTP"
      responses:
        "200":
          description: The updated MFA config.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/EnvelopedMFAConfig"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/NotAuthenticated"
        "403":
          $ref: "#/components/responses/Forbidden"
        "500":
          $ref: "#/components/responses/InternalServerError"

  /auth/mfa/preferredType:
    put:
      summary: Sets the actor's preferred OTP type in his MFA config
      operationId: putMFAConfigPreferredType
      tags:
        - Authenticate
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/OTPType"
      responses:
        "200":
          description: The actor's MFA config preferred OTP type was set.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/EnvelopedOTPType"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/NotAuthenticated"
        "403":
          $ref: "#/components/responses/Forbidden"
        "500":
          $ref: "#/components/responses/InternalServerError"

  /auth/mfa/regenerateBackupCodes:
    put:
      summary: Regenerate the actor's backup codes
      operationId: regenerateMFABackupCodes
      tags:
        - Authenticate
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/MFAConfigRegenerateBackupCodes"
      responses:
        "200":
          description: The updated MFA config.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/EnvelopedBackupCodes"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/NotAuthenticated"
        "403":
          $ref: "#/components/responses/Forbidden"
        "500":
          $ref: "#/components/responses/InternalServerError"

  /login/methods:
    get:
      summary: Retrieve the available login methods for a given username
      operationId: getLoginMethods
      tags:
        - Authenticate
      security: []
      parameters:
        - $ref: "#/components/parameters/username"
      responses:
        "200":
          description: Authentication methods collection response.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/EnvelopedAuthenticationMethods"
        "400":
          $ref: "#/components/responses/BadRequest"
        "500":
          $ref: "#/components/responses/InternalServerError"
  /login:
    post:
      summary: Login (returns an OTP token if MFA is configured for the user)
      operationId: postLogin
      tags:
        - Core
        - Authenticate
      security: []
      parameters: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/Login"
      responses:
        "200":
          description: The login succeeded.
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: "#/components/schemas/EnvelopedLoginOTPOutput"
                  - $ref: "#/components/schemas/EnvelopedLoginGDPROutput"
                  - $ref: "#/components/schemas/EnvelopedLoginMFAOutput"
                  - $ref: "#/components/schemas/EnvelopedLoginAccessOutput"
        "400":
          $ref: "#/components/responses/BadRequest"
        "403":
          $ref: "#/components/responses/Forbidden"
        "500":
          $ref: "#/components/responses/InternalServerError"

  /login/otp:
    post:
      summary: Confirm login with OTP
      operationId: postLoginOTP
      tags:
        - Core
        - Authenticate
      security:
        - otp_token: []
      parameters: []
      requestBody:
        content:
          application/json:
            schema:
              oneOf:
                - $ref: "#/components/schemas/LoginOTPInput"
                - $ref: "#/components/schemas/LoginBackupCodeInput"
      responses:
        "200":
          description: The login succeeded.
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: "#/components/schemas/EnvelopedLoginGDPROutput"
                  - $ref: "#/components/schemas/EnvelopedLoginAccessOutput"
        "400":
          $ref: "#/components/responses/BadRequest"
        "403":
          $ref: "#/components/responses/Forbidden"
        "500":
          $ref: "#/components/responses/InternalServerError"

  /login/resendOTP:
    post:
      summary: Request a new OTP code for login
      operationId: requestNewLoginOTPCode
      tags:
        - Authenticate
      security:
        - otp_token: []
      responses:
        "204":
          description: The OTP code was resent.
        "401":
          $ref: "#/components/responses/NotAuthenticated"
        "403":
          $ref: "#/components/responses/Forbidden"
        "429":
          description: Too many requests.
        "500":
          $ref: "#/components/responses/InternalServerError"

  /login/refresh:
    post:
      summary: Refresh the access token
      operationId: postLoginRefresh
      tags:
        - Management
        - Authenticate
      security:
        - refresh_token: []
      parameters: []
      requestBody:
        content:
          application/json:
            schema:
              type: object
              description: The old access token.
              properties:
                access_token:
                  $ref: "#/components/schemas/AccessToken"
      responses:
        "200":
          description: The refresh succeeded.
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: "#/components/schemas/EnvelopedLoginGDPROutput"
                  - $ref: "#/components/schemas/EnvelopedLoginRefreshOutput"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/NotAuthenticated"
        "403":
          $ref: "#/components/responses/Forbidden"
        "500":
          $ref: "#/components/responses/InternalServerError"

  /login/sso/azure:
    post:
      summary: Login with Azure SSO
      operationId: postLoginWithAzureSSO
      tags:
        - Authenticate
      security: []
      parameters: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/AzureSSOLogin"
      responses:
        "200":
          description: The login succeeded.
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: "#/components/schemas/EnvelopedLoginGDPROutput"
                  - $ref: "#/components/schemas/EnvelopedLoginAccessOutput"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/NotAuthenticated"
        "403":
          $ref: "#/components/responses/Forbidden"
        "500":
          $ref: "#/components/responses/InternalServerError"

  /login/sso/google:
    post:
      summary: Login with Google SSO
      operationId: postLoginWithGoogleSSO
      tags:
        - Authenticate
      security: []
      parameters: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/GoogleSSOLogin"
      responses:
        "200":
          description: The login succeeded.
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: "#/components/schemas/EnvelopedLoginGDPROutput"
                  - $ref: "#/components/schemas/EnvelopedLoginAccessOutput"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/NotAuthenticated"
        "403":
          $ref: "#/components/responses/Forbidden"
        "500":
          $ref: "#/components/responses/InternalServerError"

  /agencies/{agencyId}/plans:
    parameters:
      - $ref: "#/components/parameters/agencyId"
    get:
      summary: Retrieves a collection of plans
      description: |
        At the moment, retrieving a collection of plans is not paginated by default.
        The paging is performed when at least one of the paging query parameters (`page` or `itemsPerPage`) is
        present with a valid value.
        The default values are used like this:
        - if `page` is present and `itemsPerPage` is absent, the paging is performed with a default value for `itemsPerPage`,
        - if `itemsPerPage` is present and `page` is absent, the paging is performed with a default value for `page`,
        - but if both `page` and `itemsPerPage` are absent, no paging is performed.
      operationId: getPlans
      tags:
        - Plan
      parameters:
        - $ref: "#/components/parameters/page"
        - $ref: "#/components/parameters/itemsPerPage"
        - $ref: "#/components/parameters/archived"
      responses:
        "200":
          description: Plan collection response in a light representation.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/EnvelopedPlansLight"
        "401":
          $ref: "#/components/responses/NotAuthenticated"
        "403":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"
        "500":
          $ref: "#/components/responses/InternalServerError"

  /agencies/{agencyId}/plans/{planId}:
    parameters:
      - $ref: "#/components/parameters/agencyId"
      - $ref: "#/components/parameters/planId"
    get:
      summary: Retrieve a plan
      operationId: getPlan
      tags:
        - Plan
      parameters:
        - $ref: "#/components/parameters/planMode"
      responses:
        "200":
          description: Plan response.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/EnvelopedPlan"
        "401":
          $ref: "#/components/responses/NotAuthenticated"
        "403":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"
        "500":
          $ref: "#/components/responses/InternalServerError"
    put:
      summary: Create or update a plan
      operationId: putPlan
      tags:
        - Core
        - Plan
      parameters:
        - $ref: "#/components/parameters/force"
      requestBody:
        description: The Plan to update.
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/Plan"
      responses:
        "200":
          description: Plan response updated.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/EnvelopedPlan"
        "201":
          description: Plan response created.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/EnvelopedPlan"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/NotAuthenticated"
        "403":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"
        "500":
          $ref: "#/components/responses/InternalServerError"
    delete:
      summary: Delete a plan
      operationId: deletePlan
      tags:
        - Plan
      responses:
        "204":
          description: Plan is deleted and no content is returned.
        "401":
          $ref: "#/components/responses/NotAuthenticated"
        "403":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"
        "500":
          $ref: "#/components/responses/InternalServerError"

  /agencies/{agencyId}/plans/{planId}/running:
    parameters:
      - $ref: "#/components/parameters/agencyId"
      - $ref: "#/components/parameters/planId"
    put:
      summary: Stop or restart the optimization of a plan
      operationId: putPlanRunning
      tags:
        - Management
        - Plan
      parameters:
        - $ref: "#/components/parameters/force"
      requestBody:
        description: "A boolean value: false will stop the optimization, true will restart the optimization."
        content:
          application/json:
            schema:
              type: boolean
              example: false
      responses:
        "200":
          description: The request succeeded.
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/NotAuthenticated"
        "403":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"
        "500":
          $ref: "#/components/responses/InternalServerError"

  /agencies/{agencyId}/plans/{planId}/resources/{resourceId}:
    parameters:
      - $ref: "#/components/parameters/agencyId"
      - $ref: "#/components/parameters/planId"
      - $ref: "#/components/parameters/resourceId"
    get:
      summary: Retrieve a plan's resource
      operationId: getPlanResource
      tags:
        - Resource
      responses:
        "200":
          description: Resource response.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/EnvelopedResource"
        "401":
          $ref: "#/components/responses/NotAuthenticated"
        "403":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"
        "500":
          $ref: "#/components/responses/InternalServerError"
    put:
      summary: Create or update a plan's resource
      operationId: putPlanResource
      tags:
        - Resource
      parameters:
        - $ref: "#/components/parameters/force"
      requestBody:
        description: The Resource to update.
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/Resource"
      responses:
        "200":
          description: Resource response updated.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/EnvelopedResource"
        "201":
          description: Resource response created.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/EnvelopedResource"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/NotAuthenticated"
        "403":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"
        "500":
          $ref: "#/components/responses/InternalServerError"
    delete:
      summary: Delete a plan's resource
      operationId: deletePlanResource
      tags:
        - Resource
      parameters:
        - $ref: "#/components/parameters/force"
      responses:
        "204":
          description: Resource is deleted and No content is returned.
        "401":
          $ref: "#/components/responses/NotAuthenticated"
        "403":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"
        "500":
          $ref: "#/components/responses/InternalServerError"

  /agencies/{agencyId}/plans/{planId}/resources/{resourceId}/state:
    parameters:
      - $ref: "#/components/parameters/agencyId"
      - $ref: "#/components/parameters/planId"
      - $ref: "#/components/parameters/resourceId"
    get:
      summary: Retrieve a plan's resource state
      operationId: getPlanResourceState
      tags:
        - Resource
      responses:
        "200":
          description: State response.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/EnvelopedState"
        "401":
          $ref: "#/components/responses/NotAuthenticated"
        "403":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"
        "500":
          $ref: "#/components/responses/InternalServerError"
    put:
      summary: Update a plan's resource state
      operationId: putPlanResourceState
      tags:
        - Resource
      parameters:
        - $ref: "#/components/parameters/force"
      requestBody:
        description: The State to update.
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/State"
      responses:
        "200":
          description: State response updated.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/EnvelopedState"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/NotAuthenticated"
        "403":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"
        "500":
          $ref: "#/components/responses/InternalServerError"

  /agencies/{agencyId}/plans/{planId}/resources/{resourceId}/forbid/{stopId}:
    parameters:
      - $ref: "#/components/parameters/agencyId"
      - $ref: "#/components/parameters/planId"
      - $ref: "#/components/parameters/resourceId"
      - $ref: "#/components/parameters/stopId"
    put:
      summary: Forbid a resource from doing a stop, and return the updated plan
      description: |
        Forbidding a resource from doing a stop is performed internally by adding a forbidden assignment in the
        list of additional constraints of the plan. The forbidden assignment relies on:
        - a generated resource tag, based on the id of the resource (example: `generatedTag:$resource-2$:forbid`),
        - a generated stop tag, based on the id of the parent order of the stop (example: `generatedTag:$order-1$:forbid`).

        Important: all the sibling stops receive this same stop tag, which means that **all the stops of
        the order become forbidden for the resource**.
      operationId: putForbidResourceStop
      tags:
        - Resource
      parameters:
        - $ref: "#/components/parameters/force"
      responses:
        "200":
          description: Updated plan response.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/EnvelopedPlan"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/NotAuthenticated"
        "403":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"
        "500":
          $ref: "#/components/responses/InternalServerError"

  /agencies/{agencyId}/plans/{planId}/orders/{orderId}:
    parameters:
      - $ref: "#/components/parameters/agencyId"
      - $ref: "#/components/parameters/planId"
      - $ref: "#/components/parameters/orderId"
    get:
      summary: Retrieve a plan's order
      operationId: getPlanOrder
      tags:
        - Order
      responses:
        "200":
          description: Order response.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/EnvelopedOrder"
        "401":
          $ref: "#/components/responses/NotAuthenticated"
        "403":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"
        "500":
          $ref: "#/components/responses/InternalServerError"
    put:
      summary: Create or update a plan's order
      operationId: putPlanOrder
      tags:
        - Order
      parameters:
        - $ref: "#/components/parameters/force"
      requestBody:
        description: The Order to update.
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/Order"
      responses:
        "200":
          description: Order response updated.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/EnvelopedOrder"
        "201":
          description: Order response created.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/EnvelopedOrder"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/NotAuthenticated"
        "403":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"
        "500":
          $ref: "#/components/responses/InternalServerError"
    delete:
      summary: Delete a plan's order
      operationId: deletePlanOrder
      tags:
        - Order
      parameters:
        - $ref: "#/components/parameters/force"
      responses:
        "204":
          description: Order is deleted and no content is returned.
        "401":
          $ref: "#/components/responses/NotAuthenticated"
        "403":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"
        "500":
          $ref: "#/components/responses/InternalServerError"

  /agencies/{agencyId}/plans/{planId}/solution:
    parameters:
      - $ref: "#/components/parameters/agencyId"
      - $ref: "#/components/parameters/planId"
    get:
      summary: Retrieve a plan solution
      operationId: getPlanSolution
      tags:
        - Core
        - Plan
        - Solution
      responses:
        "200":
          description: Solution response.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/EnvelopedSolution"
        "401":
          $ref: "#/components/responses/NotAuthenticated"
        "403":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"
        "500":
          $ref: "#/components/responses/InternalServerError"

  /agencies/{agencyId}/plans/{planId}/solution/objectives:
    parameters:
      - $ref: "#/components/parameters/agencyId"
      - $ref: "#/components/parameters/planId"
    get:
      summary: Retrieve the objectives of a plan solution
      operationId: getPlanSolutionObjectives
      tags:
        - Plan
        - Solution
      responses:
        "200":
          description: Solution objectives response.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/EnvelopedSolutionObjectives"
        "401":
          $ref: "#/components/responses/NotAuthenticated"
        "403":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"
        "500":
          $ref: "#/components/responses/InternalServerError"

  /agencies/{agencyId}/plans/{planId}/state:
    parameters:
      - $ref: "#/components/parameters/agencyId"
      - $ref: "#/components/parameters/planId"
    get:
      summary: Fetch the latest state of a plan
      operationId: fetchLastPlanState
      tags:
        - Management
        - Plan
      responses:
        "200":
          description: Latest plan state.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/EnvelopedTimedPlanState"
        "401":
          $ref: "#/components/responses/NotAuthenticated"
        "403":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"
        "500":
          $ref: "#/components/responses/InternalServerError"

  /agencies/{agencyId}/plans/{planId}/states:
    parameters:
      - $ref: "#/components/parameters/agencyId"
      - $ref: "#/components/parameters/planId"
      - $ref: "#/components/parameters/limit"
    get:
      summary: Fetch the latest states of a plan
      operationId: fetchLastNPlanStates
      tags:
        - Management
        - Plan
      responses:
        "200":
          description: Latest plan states.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/EnvelopedTimedPlanStates"
        "401":
          $ref: "#/components/responses/NotAuthenticated"
        "403":
          $ref: "#/components/responses/Unauthorized"
        "500":
          $ref: "#/components/responses/InternalServerError"

  /agencies/{agencyId}/plans/{planId}/status:
    parameters:
      - $ref: "#/components/parameters/agencyId"
      - $ref: "#/components/parameters/planId"
    get:
      summary: Retrieve a plan status
      operationId: getPlanStatus
      tags:
        - Management
        - Plan
      responses:
        "200":
          description: Plan status response.
          content:
            application/json:
              schema:
                $ref: "#/c

# --- truncated at 32 KB (178 KB total) ---
# Full source: https://raw.githubusercontent.com/api-evangelist/kardinal/refs/heads/main/openapi/kardinal-aro-openapi-original.yml