# Managed Care Review - API Changelog ## This document highlights API changes that have been introduced since May 2025. See the full [GraphQL schema](services/app-graphql/src/schema.graphql). ### June 12, 2026 #### Updated - `createContractQuestion` and `createRateQuestion` now reject a new question while a previous question round is still open. - A question round is considered open when any existing question on the same contract (for `createContractQuestion`) or rate (for `createRateQuestion`) has not yet received a response. - All existing questions must be answered before a new question can be created. - New `BAD_USER_INPUT` error when createContractQuestion or createRateQuestion are called when an open round exists - The open-round check is enforced at the database level with a row lock on the parent contract or rate, so two concurrent requests cannot both create a question round. ### May 28, 2026 #### Updated - `createContractQuestion` now rejects EQRO contract questions from CMS users who are not assigned to the `DMCO` division. - Applies only to `EQRO` submissions. - `HEALTH_PLAN` submissions continue to allow contract questions from CMS users in any assigned CMS division. - API clients should expect a `FORBIDDEN` error when a non-`DMCO` CMS user attempts to create a question for an `EQRO` contract. ### May 13, 2026 #### Updated - Renamed mutation `reverseUnlockContract` to `undoUnlockContract` - This is an API-surface terminology update only. Behavior is unchanged. - Renamed associated GraphQL types: - `ReverseUnlockContractInput` -> `UndoUnlockContractInput` - `ReverseUnlockContractPayload` -> `UndoUnlockContractPayload` - The mutation still restores an unlocked contract submission to its prior submitted or resubmitted state without creating a new `packageSubmission`. ### May 8, 2026 #### Added - New mutation `reverseUnlockContract` added to the API - Reverses a previously unlocked contract submission by returning the contract to its prior submitted or resubmitted state. The reverse-unlock action is internal-only revision history and does not create a new `packageSubmission`. - Reversing unlock also restores child rates unlocked with the contract and removes linked draft rates from the changes to the submission while it was unlocked. - Parameters (via `ReverseUnlockContractInput`) - `contractID`: required ID, the ID of the contract to reverse unlock for - `updatedReason`: required String, the reason for reversing the unlock - Returns `ReverseUnlockContractPayload` - `contract`: Contract - Errors - `ForbiddenError`: A non-CMS or non-Admin user called this - `UserInputError`: The contract is not currently `UNLOCKED` - `INTERNAL_SERVER_ERROR`: DB_ERROR — a contract cannot be found by id or the reverse unlock could not be completed ### April 28, 2026 #### Added - New endpoint `indexRatesPaginated` added to the API for paginated submitted-rate results. The API can be called with no input parameters, and a default page size of 10 will be used. - Accepts the new object `IndexRatesPaginatedInput` - The new object contains the same optional filter parameters that `IndexRatesInput` accepts: - `stateCode`: optional state filter for CMS and admin users - `rateIDs`: optional list of rate IDs to limit the result set - The new object also contains pagination specific arguments: - `pageSize`: optional page size, default is 10, max is 150 - `after`: optional opaque cursor for fetching the next page - Returns `RateConnection` - `totalCount`: total number of matching submitted rates - `totalPages`: total number of pages based on totalCount and requested page size - `edges`: list of `RateConnectionEdge` - `pageInfo`: pagination metadata with `hasNextPage` and `endCursor` - `RateConnectionEdge` includes: - `cursor`: opaque cursor for the current edge - `node`: the `Rate` - Usage examples and cursor behavior are documented in [indexRatesPaginated pagination](docs/technical-design/index-rates-pagination.md). - Existing `indexRates` behavior is unchanged and remains available as the non-paginated query. ### May 6, 2026 #### Added - New mutation `deleteContractQuestion` added to the API - Soft-deletes a contract question by recording a `DELETE` action in the question's audit log. The question is not removed from the database, and subsequent reads filter it out based on the latest audit log action. - Deleting a contract question also cascades soft-deletes to any active related question documents, question responses, and question response documents by recording `CASCADE_DELETE` actions for those records. - Parameters (via `DeleteContractQuestionInput`) - `questionID`: required ID, the ID of the contract question to soft delete - `reason`: required String, the reason recorded on the delete action - Returns `DeleteContractQuestionPayload` - `question`: ContractQuestion - Errors - `ForbiddenError`: A non-AdminUser called this - `UserInputError`: A question cannot be found with the given `questionID` ### April 24, 2026 #### Updated - **`withdrawContract`** endpoint now accepts contracts with a consolidated status of `NOT_SUBJECT_TO_REVIEW` in addition to `SUBMITTED` and `RESUBMITTED`. Applies to EQRO submissions with no review-triggering provisions and CHIP-only `HEALTH_PLAN` submissions. - **`undoWithdrawContract`** endpoint re-runs review determination after undoing a withdrawal. Submissions that qualify as `NOT_SUBJECT_TO_REVIEW` (EQRO with no review-triggering provisions, CHIP-only `HEALTH_PLAN`) are restored to `NOT_SUBJECT_TO_REVIEW` rather than `UNDER_REVIEW`. ### April 20, 2026 #### Updated - **`indexRates`** endpoint updated to accept an optional `rateIDs` parameter (via `IndexRatesInput`): - **`rateIDs`**: an optional array of rate ID strings. When provided, only rates matching those IDs are returned. Useful for batch-fetching a known set of rates in a single request. - When omitted, behavior is unchanged — all submitted rates are returned (filtered by state for state users). - Draft rates are excluded from results regardless of whether their ID is in the list. ### April 1, 2026 #### Added - `isDeprecated` and `deprecatedByProgramId` added to the `Program` GraphQL type. - `isDeprecated` required `Boolean`, indicates whether the program has been retired from new selection. - `deprecatedByProgramId` nullable `String`, optionally identifies the replacement program when one exists. - Affected endpoints: - `fetchCurrentUser` - `fetchContract` - `fetchRate` - `fetchMcReviewSettings` - `indexContracts` - `indexContractsStripped` - `indexRates` - `indexRatesStripped` - `indexUsers` ### March 16, 2026 #### Added - New mutation `undoApproveContract` added to the API - Undoes the approval of a previously approved contract. CMS users only. - Parameters (via `UndoApproveContractInput`) - `contractID`: required ID, the ID of the contract to undo approval for - `updatedReason`: required String, the reason for undoing the approval - Returns `UndoApproveContractPayload` - `contract`: Contract - Errors - `ForbiddenError`: A non-CMS or non-Admin user called this - `UserInputError`: The contract is not in an approved status, or the latest review action is not `MARK_AS_APPROVED` - `INTERNAL_SERVER_ERROR`: DB_ERROR — a contract cannot be found by id ### March 12, 2026 #### Added - New endpoint `generateUploadURL` added to the API - Parameters - `fileName`: required String, the full name of the file including extension - `fileType`: required enum, corresponds to the file's extension, possible values: `[PDF, DOC, DOCX, XLS, XLSX, XLSM, CSV]` - `bucketName`: required enum, corresponds to the bucket the file should be uploaded to, possible values: `[HEALTH_PLAN_DOCS, QUESTION_ANSWER_DOCS]` - Returns - bucket: String - expiresIn: Int - s3Key: String - s3URL: String - uploadURL: String ### January 29, 2026 #### Added - New submission status of `NOT_SUBJECT_TO_REVIEW`. For EQRO submissions that do not require CMS review. - `NOT_SUBJECT_TO_REVIEW` to the enum `ContractReviewStatus` in GraphQL. - `NOT_SUBJECT_TO_REVIEW` to the enum `ConsolidatedContractStatus` in GraphQL. - `NOT_SUBJECT_TO_REVIEW` to the enum `ContractActionType` in GraphQL. #### Updated - `ContractReviewStatusActions` GraphQL type. - `updatedBy` field is now optional. ### November 13, 2025 #### Added - `EQRO` contract submission type fields to `ContractFormData` GraphQL type. ```graphql type ContractFormData { ...existing fields, "If contract has a new EQRO contractor" eqroNewContractor: Boolean "If new optional activities to be performed on MCOs" eqroProvisionMcoNewOptionalActivity: Boolean "If new MCO managed care program has EQR-related activities" eqroProvisionNewMcoEqrRelatedActivities: Boolean "If EQR-related activities are performed on the CHIP population" eqroProvisionChipEqrRelatedActivities: Boolean "EQR or EQR-related activities are performed on MCOs" eqroProvisionMcoEqrOrRelatedActivities: Boolean } ``` - These new fields on the `ContractFormData` are `EQRO` contract submission form fields. They are questions asked for `EQRO` contract submissions only in the MC-Review state portal app. - Affected endpoints: - `fetchContract` - `indexContracts` - `fetchRate` - `indexRates` ### October 30, 2025 #### Added - `contractSubmissionType` to the `Contract` and `UnlockedContract` GraphQL type. - `contractSubmissionType` label the contract type of the submission. At this time there are two types a contract can be `HEALTH_PLAN` and `EQRO`. - Affected endpoints: - `fetchContract` - `indexContracts` ### October 16, 2025 #### Updated - **IndexContracts** endpoint updated to accept 2 optional parameters: - **updatedWithin**: an integer, representing seconds. Only submissions that have been updated within the specified timeframe will be returned - **statusesToExclude**: An array of statuses to exclude in the filtered results. Valid statuses include: - DRAFT - SUBMITTED - UNLOCKED - RESUBMITTED - APPROVED - WITHDRAWN ### September 4, 2025 #### Added - **ID** field added to `Document` GraphQL type (optional) - The Document type is used for Q&A document responses - API endpoints that return Document data will now include the document ID when available - **Affected endpoints:** - `fetchContract` - `fetchRate` - `fetchDocument` ### August 25, 2025 #### Added - New endpoint `fetchDocument` added to the API - Parameters - `documentID`: the `id` of the document to be retrieved - `documentType`: optional field that represents the type of document to be retrieved. Can be one of: CONTRACT_DOC, CONTRACT_SUPPORTING_DOC, RATE_DOC, RATE_SUPPORTING_DOC, CONTRACT_QUESTION_DOC, CONTRACT_QUESTION_RESPONSE_DOC, RATE_QUESTION_DOC, RATE_QUESTION_RESPONSE_DOC. Using this parameter gives a performance boost - `expiresIn`: represents times in seconds until the downloadURL's expiration. Valid range from 1 second to 604,800 seconds (1 week). Defaults to 3600 seconds (1 hour) - Returns a SharedDocument type - id: String - name: String - s3URL: String - sha256: String - downloadURL: String ### July 9, 2025 #### Added - `rateMedicaidPopulations` optional array field, possible values: `["MEDICARE_MEDICAID_WITH_DSNP", "MEDICAID_ONLY", "MEDICARE_MEDICAID_WITHOUT_DSNP"]`, added to `formData` on `RateRevision`. This change affects all queries and mutations that include `RateFormData` ### June 27, 2025 #### Added - `dsnpContract` optional field (`boolean` type) added to `formData` on `ContractRevision`. This change affects all queries and mutations that include `ContractFormData` ### June 20, 2025 #### Added - `round` field (`int` type) added to `RateQuestion` ### June 9, 2025 #### Added - `id` field added to `GenericDocument` ### May 9, 2025 #### Deleted - `withdrawInfo` field was removed from `Rate` - `withdrawInfo` field was removed from `RateStripped` ### May 2, 2025 #### Deleted - `withdrawAndReplaceRedundantRate` endpoint deleted. It was an Admin only action that was used to address bookkeeping errors with rates