openapi: 3.0.2 info: description: >- This API is meant for provisioning resources in a target Cloud Environment in a vendor-agnostic fashion. By implementing this API, vendors make it possible to automatically provision accounts via ATAT. ## Portfolios Portfolios represent a logical container for a group of related Environments and the Task Orders/CLINs which fund them. As a general rule, everything within a given Portfolio is part of the same overall Mission or Program. ## Environments Environments represent a logical container for a set of cloud resources which are funded by a particular CLIN within a Task Order. The term is meant to be agnostic across CSPs. An Environment can be thought of as an account at the root of a hierarchy. ATAT does not dictate structure within a Portfolio. Once an Environment has been provisioned a Mission Owner is free to organize and secure resources to satisfy mission requirements. ## Task Orders Portfolios contain one or more *Task Orders* (TO), which in turn contain one or more *Contract Line Item Numbers* (CLINs). Each have separate Periods of Performance (PoP) dates; CLIN PoP dates will be within the time frames of the Task Order in which they belong. ## Cost reporting Provisioned resources incur costs with participating CSPs. Costs related to provisioned resources can be attributed to specific CLINs. Actual and forecasted CSP costs can be reported by CLIN. version: 1.3.2 title: ATAT CSP API contact: email: disa.meade.hacc.list.hc2-atat-dev-provisioning-api@mail.mil tags: - name: access description: >- Operations to manage access to provisioned Environments - name: cost description: >- Operations to query for actual and forecasted costs - name: provisioning description: >- Operations to manage provisioned Environments paths: '/portfolios': parameters: - $ref: '#/components/parameters/ApiVersion' post: tags: - provisioning summary: Adds a new Portfolio security: - oidc: [atat/write-portfolio] description: >- Adds a new Portfolio to be provisioned, including Task Orders and Operators. Once provisioned, Operators can log in to the CSP and begin using provisioned resources and services, funded by the provided Task Order(s). Note that invitations should be sent to all Operator email addresses included in the request. See [#/info/description](#/info/description) and [#/components/schemas](#/components/schemas) for details of these constructs. operationId: addPortfolio requestBody: description: A new Portfolio required: true content: application/json: schema: $ref: '#/components/schemas/PortfolioCreate' responses: '200': description: Portfolio response object content: application/json: schema: $ref: '#/components/schemas/PortfolioCreate' '400': description: Invalid input '405': description: Not ready to provision '/portfolios/{portfolioId}': parameters: - $ref: '#/components/parameters/ApiVersion' - $ref: '#/components/parameters/PortfolioId' get: tags: - provisioning summary: Gets an existing Portfolio security: - oidc: [atat/read-portfolio] description: Returns a single existing Portfolio, including Task Orders and Operators operationId: getPortfolioById responses: '200': description: Portfolio successfully retrieved content: application/json: schema: $ref: '#/components/schemas/Portfolio' '400': description: Invalid ID supplied '404': description: Portfolio not found '/portfolios/{portfolioId}/costs': parameters: - $ref: '#/components/parameters/ApiVersion' - $ref: '#/components/parameters/PortfolioId' get: tags: - cost summary: Returns cost data for a Portfolio, broken down by Task Order & CLINs security: - oidc: [atat/read-cost] description: >- Queries CSP for actual or forecasted cost data across a Portfolio. Queries should return data for all months included in date ranges. For example, a `start_date` of "2022-01-25" and `end_date` of "2022-03-02" should return data for January, February and March. It is expected that actual results will be provided for all months which have been invoiced while forecast data will be provided for all future months. operationId: getCostsByPortfolio parameters: - name: start_date in: query description: >- Start date of the cost data request in YYYY-MM format. Must not precede the earliest `pop_start_date` of the given Portfolio's Task Orders. required: true schema: type: string format: date example: "2023-12" - name: end_date in: query description: >- End date of the cost data request in YYYY-MM format. Must not exceed the latest `pop_end_date` of the given Portfolio's Task Orders. required: true schema: type: string format: date example: "2026-12" responses: '200': description: Cost operation successful content: application/json: schema: $ref: '#/components/schemas/CostResponseByPortfolio' examples: CostResponseActual: $ref: '#/components/examples/CostResponseByPortfolio' '400': description: Invalid ID or query parameters '404': description: Portfolio not found '/portfolios/{portfolioId}/task-orders': parameters: - $ref: '#/components/parameters/ApiVersion' - $ref: '#/components/parameters/PortfolioId' post: tags: - provisioning summary: Adds a new Task Order (TO) security: - oidc: [atat/write-portfolio] description: Adds a new Task Order to an existing Portfolio operationId: addTaskOrder responses: '200': description: Successful operation content: application/json: schema: $ref: '#/components/schemas/TaskOrder' '400': description: Invalid ID supplied '404': description: Portfolio not found '405': description: Not ready to provision requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/TaskOrder' '/portfolios/{portfolioId}/task-orders/{taskOrderId}': parameters: - $ref: '#/components/parameters/ApiVersion' - $ref: '#/components/parameters/PortfolioId' - $ref: '#/components/parameters/TaskOrderId' put: tags: - provisioning summary: Updates an existing Task Order (TO) security: - oidc: [atat/write-portfolio] description: Updates an existing Task Order (TO) operationId: updateTaskOrder responses: '200': description: Successful operation content: application/json: schema: $ref: '#/components/schemas/TaskOrder' '400': description: Invalid ID supplied '404': description: Portfolio or Task Order not found '405': description: Not ready to provision requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/TaskOrder' '/portfolios/{portfolioId}/task-orders/{taskOrderId}/clins/{clin}/costs': parameters: - $ref: '#/components/parameters/ApiVersion' - $ref: '#/components/parameters/PortfolioId' - $ref: '#/components/parameters/TaskOrderId' get: tags: - cost summary: Returns cost data by CLIN security: - oidc: [atat/read-cost] description: Queries CSP for actual or forecasted cost data by CLIN operationId: getCostsByCLIN parameters: - name: clin in: path description: Contract Line Item Number required: true schema: type: string - name: start_date in: query description: >- Start date of the cost data request in YYYY-MM format. Must not precede the earliest `pop_start_date` of the given CLIN. required: true schema: type: string format: date example: "2023-12" - name: end_date in: query description: >- End date of the cost data request in YYYY-MM format. Must not exceed the latest `pop_end_date` of the given CLIN. required: true schema: type: string format: date example: "2026-12" responses: '200': description: Cost operation successful content: application/json: schema: $ref: '#/components/schemas/CostResponseByCLIN' examples: CostResponseActual: $ref: '#/components/examples/CostResponseByCLIN' '400': description: Invalid ID or query parameters '404': description: Portfolio not found '/portfolios/{portfolioId}/environments': parameters: - $ref: '#/components/parameters/ApiVersion' - $ref: '#/components/parameters/PortfolioId' post: tags: - provisioning summary: Adds a new Environment to an existing Portfolio security: - oidc: [atat/write-portfolio] description: >- Adds a new Environment to be provisioned. Once provisioned, Operators can log in to the CSP and begin using provisioned resources and services, funded by the given CLIN. **Note** * Invitations should be sent to all Operator email addresses included in the request. See [#/info/description](#/info/description) and [#/components/schemas](#/components/schemas) for details of these constructs. * If this Portfolio does not contain a CLIN whose `classification_level` matches that of the given Environment, vendors should return a HTTP 400 response. operationId: addEnvironment parameters: - name: X-Provision-Deadline description: >- The deadline by which the ATAT client expects the portfolio provisioning process to be complete is dictated by the following values: | Classification Level | Deadline | | ------------------------ | ------------| | Unclassified | 2 Hours | | Secret | 72 Hours | | Top Secret | 72 Hours | Note: this header must NOT be sent if `is_migration` is `true` for the given Environment. in: header schema: type: string format: date-time responses: '200': description: Successful operation content: application/json: schema: $ref: '#/components/schemas/EnvironmentResponse' '202': description: Provisioning request has been accepted content: application/json: schema: $ref: '#/components/schemas/ProvisioningStatus' headers: Location: description: >- Endpoint which ATAT should poll to receive status updates for this provisioning job. This must be the getProvisioningStatus endpoint for this creation request. schema: type: string example: "https://csp.com/atat/provisioning/123456789/status" required: true '400': description: Invalid ID supplied '404': description: Portfolio not found '405': description: Not ready to provision requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/Environment' '/portfolios/{portfolioId}/environments/{environmentId}': parameters: - $ref: '#/components/parameters/ApiVersion' - $ref: '#/components/parameters/PortfolioId' - $ref: '#/components/parameters/EnvironmentId' get: tags: - access summary: Get the Environment object by the EnvironmentId. security: - oidc: [atat/read-portfolio] description: >- Returns a single existing Environment operationId: getEnvironmentById responses: '200': description: Environment successfully retrieved content: application/json: schema: $ref: '#/components/schemas/EnvironmentResponse' '400': description: Invalid ID supplied '404': description: Portfolio or Environment not found '/provisioning/{provisioningJobId}/status': parameters: - $ref: '#/components/parameters/ApiVersion' get: tags: - provisioning summary: Get the status of a previously issued provisioning job security: - oidc: [atat/read-portfolio] description: >- Queries the CSP for the status of a previously issued provisioning job for which that CSP issued an HTTP 202 response, indicating that the provisioning job was accepted but a response was not available immediately. This allows continuously checking the status to inform the end user. The provisioning job ID must be unique across all provisioning jobs and must never be reused; however, a provisioning job ID must be queryable for at least 168 but no more than 240 hours. operationId: getProvisioningStatus parameters: - name: provisioningJobId in: path description: The ID of the provisioning job required: true schema: type: string responses: '200': description: Get provisioning status successful content: application/json: schema: $ref: '#/components/schemas/ProvisioningStatus' '404': description: Provisioning Job ID not found '/far51': parameters: - $ref: '#/components/parameters/ApiVersion' get: tags: - cost summary: Gets all FAR Part 51 Authorizations security: - oidc: [atat/read-portfolio] description: >- Returns an array of FAR Part 51 Authorizations known to the vendor, so that the ATAT client can track them. This information must be provided in this way (sourced by the vendor rather than the ATAT client) because FAR Part 51 Authorizations are not processed through the ATAT UI in the same fashion as Portfolios, Task Orders and Environments. Must return an array of FAR Part 51 Authorizations, subject to the `limit` and `offset` pagination parameters as well as the `start_date` and `end_date` query parameters, sorted by `created_at`. operationId: getFarPart51Authorizations parameters: - name: start_date in: query description: >- Start date of the request in YYYY-MM format (inclusive). Earliest allowed value is `2023-01`. required: true schema: type: string format: date example: "2023-12" - name: end_date in: query description: >- End date of the request in YYYY-MM format (inclusive). required: true schema: type: string format: date example: "2026-12" - $ref: '#/components/parameters/Limit' - $ref: '#/components/parameters/Offset' responses: '200': description: FAR Part 51 Authorizations successfully retrieved content: application/json: schema: type: array maxItems: 100 uniqueItems: true items: $ref: '#/components/schemas/Far51Authorization' '400': description: Missing required parameter or invalid parameter '/far51/{far51AuthorizationId}/costs': parameters: - $ref: '#/components/parameters/ApiVersion' get: tags: - cost summary: Returns cost data for a FAR 51 Authorization security: - oidc: [atat/read-cost] description: >- Queries CSP for actual cost data for a given FAR Part 51 Authorization and time period. Queries should return data for all months included in date ranges. For example, a `start_date` of "2022-01-25" and `end_date` of "2022-03-02" should return data for January, February and March. If the date range requested by the client includes periods for which no data exists, the server must return whatever matching cost data does exist rather than respond with an error code. operationId: getCostsByFar51Authorization parameters: - name: start_date in: query description: >- Start date of the cost data request in YYYY-MM format (inclusive). Earliest allowed value is `2023-01`. required: true schema: type: string format: date example: "2023-12" - name: end_date in: query description: >- End date of the cost data request in YYYY-MM format (inclusive). required: true schema: type: string format: date example: "2026-12" - name: far51AuthorizationId description: ID of the FAR Part 51 Authorization in: path required: true schema: type: string responses: '200': description: Cost operation successful content: application/json: schema: $ref: '#/components/schemas/CostData' '400': description: Invalid ID or query parameters '404': description: Far Part 51 Authorization not found components: parameters: ApiVersion: name: X-Atat-Api-Version description: >- This header may be provided by an ATAT client implementation to provide context for the ATAT API specification that it expects to be compatible with. Implementations may choose to adapt their response to conform to the expected API version. If not provided by the client, the server should assume the client supports the latest version of this specification. in: header schema: type: string Limit: name: limit description: Maximum number of results to be returned for a given request in: query schema: type: integer default: 10 minimum: 1 maximum: 100 Offset: name: offset description: Offset for use when returning the n-th page of results (0-indexed) in: query schema: type: integer default: 0 minimum: 0 PortfolioId: name: portfolioId description: ID of the Portfolio in: path required: true schema: type: string EnvironmentId: name: environmentId description: ID of the Environment in: path required: true schema: type: string TaskOrderId: name: taskOrderId in: path description: ID of the Task Order required: true schema: type: string schemas: ProvisioningStatus: type: object description: >- Represents the status of a provisioning job required: - provisioning_job_id - status properties: provisioning_job_id: type: string description: >- The ID of the Provisioning job; used for retrieving status to inform end user. This ID must be unique across all provisioning jobs across portfolios. example: "123456789" portfolio_id: type: string description: The ID of the Portfolio for which status is being returned environment_id: type: string description: The ID of the Environment for which status is being returned status: type: string enum: - NOT_STARTED - IN_PROGRESS - SUCCESS - FAILURE PortfolioCreate: description: >- Initial Portfolio created to contain Environments, which is an empty shell that does not initially include Environments. required: - id - name - task_orders properties: id: description: >- Represents the unqiue ID of the Portfolio created by the vendor. In order to enable the ATAT UI to construct links back to the provisioned environment, this should be the same ID generated internally for the vendor's Portfolio-equivalent construct. type: string readOnly: true example: "csp-portfolio-id-123" name: type: string example: "Sample Portfolio name" task_orders: type: array items: allOf: - $ref: '#/components/schemas/TaskOrder' Portfolio: allOf: - $ref: '#/components/schemas/PortfolioCreate' description: >- Logical container for a set of cloud Environments and the Task Orders/CLINs which fund them required: - id - name - task_orders - environments properties: environments: type: array items: $ref: '#/components/schemas/EnvironmentResponse' EnvironmentResponse: description: >- Logical container for a set of cloud resources which are paid for by a Task Order & its CLINs. Note that this version intentionally excludes the administrators property, because it is not considered permanent state that the client will track. required: - id - name - dashboard_link - classification_level properties: id: description: >- Represents the unique ID of the Environment created by the vendor. In order to enable the ATAT UI to construct links back to the provisioned environment, this should be the same ID generated internally for the vendor's Portfolio-equivalent construct. type: string readOnly: true example: "csp-environment-id-123" name: type: string example: "Sample Environment name" account_name: description: >- Text which is meant to represent a name that uniquely identifies this Environment in the vendor cloud which can be used in part of a host name or URL. type: string example: "sampleenvironment-a_1" pattern: '^[a-zA-Z][a-zA-Z0-9]{5,25}$' email_distribution_list: description: >- Represents an email meant to be used as a distribution list for communication from the vendor to the owners of this Environment. Should not be an individual's email address. type: string format: email example: "my-agency-mbx-program-abc-il2@agency.mil" dashboard_link: description: >- Represents a deep link to the Environment as represented in the vendor's dashboard. Allows ATAT to provide direct links to a Mission Owner's Environment within the vendor's target cloud. Will NOT be supplied by the ATAT Client on initial call to create the Environment, but is expected to be provided upon successful Environment creation. type: string readOnly: true format: uri example: "https://vendor.com/account/csp-portfolio-id-123/environment/csp-environment-id-123" classification_level: $ref: '#/components/schemas/ClassificationLevel' cloud_distinguisher: $ref: '#/components/schemas/CloudDistinguisher' is_migration: description: >- A boolean value representing whether or not the Environment being created requires the migration of existing cloud resources. type: boolean default: false Environment: description: >- Logical container for a set of cloud resources which are paid for by a Task Order & its CLINs. allOf: - $ref: '#/components/schemas/EnvironmentResponse' required: - id - name - administrators - dashboard_link - classification_level properties: administrators: type: array items: $ref: "#/components/schemas/Operator" TaskOrder: type: object description: >- A Task Order and CLINs used to pay for provisioned resources and services required: - id - task_order_number - clins - pop_start_date - pop_end_date properties: id: description: Represents the unique ID of a Task Order. Must be defined by CSPs upon object creation. type: string readOnly: true example: "csp-task-order-id-123" task_order_number: description: >- Represents the current Task Order Number. Subject to change over the lifetime of a Task Order. Should be considered metadata rather than a primary key (use the `id` instead). type: string example: "HQ003421F0024" clins: type: array items: $ref: '#/components/schemas/CLIN' pop_start_date: description: Start of period of performance for this Task Order in YYYY-MM-DD format. type: string format: date example: "2021-07-15" pop_end_date: description: End of period of performance for this Task Order in YYYY-MM-DD format. type: string format: date example: "2026-07-14" CLIN: description: >- Represents a CLIN in a Task Order. Note that `classification_level` is required if type == "CLOUD", otherwise it must be null or undefined. additionalProperties: false required: - clin_number - type - pop_start_date - pop_end_date properties: clin_number: description: Contract Line Item Number (CLIN), 0001 through 9999 type: string pattern: '(?!^0{4}$)^\d{4}$' type: description: >- Distinguishes a "CLOUD" CLIN, which directly funds cloud workloads, from "NON_CLOUD" CLINs, which do not. type: string enum: - CLOUD - NON_CLOUD classification_level: $ref: '#/components/schemas/ClassificationLevel' pop_start_date: description: Start of period of performance for this CLIN in YYYY-MM-DD format. type: string format: date example: "2021-07-22" pop_end_date: description: End of period of performance for this CLIN in YYYY-MM-DD format. type: string format: date example: "2026-07-21" Operator: description: >- Represents an individual who should have access to a Portfolio in a target Cloud Environment. required: - email - dod_id - needs_reset properties: email: type: string format: email example: "portfolio.admin@mail.mil" dod_id: type: string minLength: 10 maxLength: 10 needs_reset: description: >- Flag which denotes whether the given Operator's access should be updated (password/token reset or other vendor-specific process) type: boolean default: false ClassificationLevel: description: >- Represents the classification level for this environment. Attempts to change this field via PUT or PATCH should result in a HTTP 400. type: string enum: - UNCLASSIFIED - SECRET - TOP_SECRET Far51Authorization: description: >- An authorization to spend contract funds under FAR Part 51 (see https://www.acquisition.gov/far/part-51). properties: id: type: string description: Unique identifier for this FAR Part 51 Authorization. Used for retrieval of cost data. example: "csp-far-51-id-123" created_at: description: >- Date this FAR Part 51 Authorization was created by the vendor's ATAT implementation in YYYY-MM-DD format. type: string format: date example: "2021-03-28" contract_number: description: Contract Number under which this FAR Part 51 Authorization was granted type: string example: "N0006217D0001" delivery_order_number: description: Delivery Order Number under which this FAR Part 51 Authorization was granted type: string example: "N0006217F0001" pop_start_date: description: Start of period of performance for this FAR Part 51 Authorization in YYYY-MM-DD format. type: string format: date example: "2021-07-15" pop_end_date: description: End of period of performance for this FAR Part 51 Authorization in YYYY-MM-DD format. type: string format: date example: "2026-07-14" customer_department: description: >- Abbreviation for Agency or Department associated with this FAR Part 51 Authorization, e.g. AF, Army, DLA, DOJ type: string example: "DOJ" authorizing_contract_officer: description: Contact information for authorizing Contract Officer type: object properties: name: type: string example: "Jane Contractor" telephone: type: string example: "555-123-4567" email: type: string format: email example: "jane@agency.gov" CostResponseByCLIN: description: >- Provides cost data in a format in accordance with the provided CostRequest. Implementors must provide actual data for any month in which real costs has been incurred, whether or not they have been invoiced. Forecast data should be supplied for any month which has not been invoiced. Specifically, this implies the following expectations: * Invoiced Past Months - actuals only * Un-invoiced Past Months - actuals and forecasts * Current Month - actuals and forecasts * Future Months - forecasts only **Note**: Forecast data is only required for CLIN's whose `type` is "CLOUD". For instance, vendors are not expected to provide forecast data for expenses such as travel or training. required: - actual properties: actual: $ref: '#/components/schemas/CostData' forecast: $ref: '#/components/schemas/CostData' CloudDistinguisher: description: >- Optional parameter used when the vendor offers more than one distinct Cloud System at a given classification level. Valid values must be provided to ATAT client by vendors. Note that it is expected that implementations will ignore the `display_name` and `description` fields. They are nonetheless included to ensure that their intent is not misrepresented by the ATAT UI. required: - name - display_name - description properties: name: type: string description: Unique identifier for a particular Cloud System, according to vendor example: il4_dod display_name: type: string description: Human readable display name for a Cloud System identifier example: Department of Defense - IL4 description: type: string description: Description of intended use of a Cloud System example: Cloud System meant for use by DoD organizations with IL4 workloads CostResponseByPortfolio: description: >- Provides cost data in a format in accordance with the provided CostRequest. Implementors must provide actual data for any month in which real costs has been incurred, whether or not they have been invoiced. Forecast data should be supplied for any month which has not been invoiced. Specifically, this implies the following expectations: * Invoiced Past Months - actuals only * Un-invoiced Past Months - actuals and forecasts * Current Month - actuals and forecasts * Future Months - forecasts only **Note**: Forecast data is only required for CLIN's whose `type` is "CLOUD". For instance, vendors are not expected to provide forecast data for expenses such as travel or training. required: - task_orders properties: task_orders: type: array items: required: - task_order_id - task_order_number - clins properties: task_order_id: type: string task_order_number: type: string clins: type: array required: - clin_number - actual items: properties: clin_number: type: string actual: $ref: '#/components/schemas/CostData' forecast: $ref: '#/components/schemas/CostData' CostData: required: - total - results properties: total: type: string description: Total cost (ACTUAL or FORECAST) for all included months in USD example: "12345.67" results: type: array items: properties: month: type: string example: "2022-12" value: type: string description: Cost (ACTUAL or FORECAST) for the given months in USD examples: CostResponseByCLIN: value: actual: total: "50.00" results: - month: "2021-10" value: "20.00" - month: "2021-11" value: "30.00" CostResponseByPortfolio: value: task_orders: - task_order_id: "abcdefghijklmnop" task_order_number: "1234567891234" clins: - clin_number: "0001" actual: total: "50.00" results: - month: "2021-12" value: "20.00" - month: "2022-01" value: "30.00" forecast: total: "100.00" results: - month: "2022-02" value: "100.00" - clin_number: "0002" actual: total: "750.00" results: - month: "2021-12" value: "50.00" - month: "2022-01" value: "700.00" securitySchemes: oidc: description: >- Represents an OIDC configuration for an Identity Provider which will be managed by the ATAT client. ATAT implementations should be configured to accept and validate tokens issued by it. Tokens will not contain information or assertions about end-user identity and should purely be used as a means for authentication of the ATAT client implementation and for authorization of that client's actions. ATAT servers must not assume that any user identities specified in request bodies (such as Mission Owners or administrators) can be authenticated using this identity provider and must only use this Identity Provider for the ATAT CSP API. ATAT implementations must leverage the OIDC discovery protocol using the provided URL and must handle key rotation automatically. ## Validation Tokens may include an Audience and if present, ATAT servers must reject any token with an incorrect Audience; however, ATAT servers must accept tokens without an Audience if otherwise valid. ATAT implementations must not limit access to specific subjects and must accept a request from a client presenting valid, unexpired, properly-scoped token. ATAT servers must ignore unrecognized attributes. ## Discovery Configuration The openIdConnectUrl below is meant for integration testing purposes only. It is expected to remain stable but may change occasionally. When this occurs, the ATAT Team will coordinate with the community and update this document as quickly as possible. type: openIdConnect openIdConnectUrl: https://cognito-idp-fips.us-gov-west-1.amazonaws.com/us-gov-west-1_2e6R3aYgi/.well-known/openid-configuration security: - oidc: - atat/read-cost - atat/read-portfolio - atat/write-portfolio