{
  "openapi": "3.0.4",
  "info": {
    "title": "SEBT.Portal.Api",
    "version": "1.0"
  },
  "paths": {
    "/api/auth/status": {
      "get": {
        "tags": [
          "Auth"
        ],
        "summary": "Returns the caller's session info read from validated JWT claims.\r\nThe JWT is carried in the HttpOnly session cookie; this endpoint exposes the\r\nnon-sensitive claims the SPA needs for IAL gating, analytics, and UI state.\r\n            \r\nAnonymous callers (no cookie, or an expired/tampered/revoked session) get\r\n200 with `isAuthorized: false` instead of a 401: the SPA probes this\r\nendpoint on every page load — including logged-out ones — so \"not signed in\"\r\nis an expected answer, not an error worth surfacing in logs and traces.\r\nBearer authentication still runs first, so an invalid session cookie is\r\nstill cleared (Set-Cookie) exactly as before.",
        "responses": {
          "200": {
            "description": "Returns session info; `isAuthorized` is false for anonymous callers.",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/AuthorizationStatusResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthorizationStatusResponse"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthorizationStatusResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/auth/logout": {
      "get": {
        "tags": [
          "Auth"
        ],
        "summary": "Revokes the surrendered session token's jti (best-effort) before clearing the local\r\nsession cookie, then redirects to the IdP's end_session_endpoint (RP-Initiated Logout)\r\nwhen OIDC is configured, or to `/login` otherwise.\r\nThe entire redirect chain is browser-level — no JavaScript processes the IdP\r\nlogout URL, eliminating XSS as a vector for redirect tampering.",
        "responses": {
          "302": {
            "description": "Found"
          }
        }
      }
    },
    "/api/auth/refresh": {
      "post": {
        "tags": [
          "Auth"
        ],
        "summary": "Refreshes the session JWT for the authenticated user. The new token is returned via\r\nthe HttpOnly session cookie; the response body carries no token.",
        "responses": {
          "204": {
            "description": "Token refreshed successfully. Cookie updated; no body."
          },
          "400": {
            "description": "Invalid request or validation error.",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "User is not authorized (missing or invalid session cookie).",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "404": {
            "description": "User not found.",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "An error occurred while refreshing the token.",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/challenges/{id}/start": {
      "get": {
        "tags": [
          "Challenges"
        ],
        "summary": "Starts a document verification challenge by generating a Socure DocV session token.\r\nCalled when the user clicks \"Continue\" on the document verification interstitial.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "The challenge's public GUID.",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "DocV session created. Returns token and URL for the frontend SDK.",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/StartChallengeResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/StartChallengeResponse"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/StartChallengeResponse"
                }
              }
            }
          },
          "401": {
            "description": "User is not authenticated.",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "Challenge not found or belongs to a different user.",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "409": {
            "description": "Challenge is not in a state that allows starting.",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        }
      }
    },
    "/api/challenges/{id}/resubmit": {
      "post": {
        "tags": [
          "Challenges"
        ],
        "summary": "Retries document verification after a Socure RESUBMIT decision (DC-301).\r\nOpens a fresh `docv_stepup` evaluation as a new challenge; the prior Resubmit\r\nchallenge stays terminal. Returns the new challenge ID + DocV URL for the user to\r\nre-capture their documents.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "The prior challenge's public GUID (must be in Resubmit state).",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Fresh challenge created. Returns new challenge ID, token, and URL.",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ResubmitChallengeResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResubmitChallengeResponse"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResubmitChallengeResponse"
                }
              }
            }
          },
          "401": {
            "description": "User is not authenticated.",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "Prior challenge not found or belongs to a different user.",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "409": {
            "description": "Prior challenge is not in Resubmit state, or step-up returned an unexpected outcome.",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "502": {
            "description": "Socure step-up call failed."
          }
        }
      }
    },
    "/api/test-error/http/{statusCode}": {
      "get": {
        "tags": [
          "Diagnostics"
        ],
        "summary": "Returns the specified HTTP status code without going through a command handler.\r\nUseful for testing frontend error-handling branches in isolation.",
        "parameters": [
          {
            "name": "statusCode",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    },
    "/api/test-error/exception": {
      "get": {
        "tags": [
          "Diagnostics"
        ],
        "summary": "Throws an unhandled System.InvalidOperationException inside SEBT.Portal.UseCases.Diagnostics.TestErrorCommandHandler.\r\nValidates that OTEL spans are marked faulted and the exception is captured in structured logs.",
        "responses": {
          "500": {
            "description": "Internal Server Error"
          }
        }
      }
    },
    "/api/test-error/exception/timeout": {
      "get": {
        "tags": [
          "Diagnostics"
        ],
        "summary": "Simulates a timeout: SEBT.Portal.UseCases.Diagnostics.TestErrorCommandHandler delays 30 seconds;\r\nthe controller cancels after 500 ms. Validates that System.OperationCanceledException\r\npropagates correctly through OTEL spans and structured logging.",
        "responses": {
          "500": {
            "description": "Internal Server Error"
          }
        }
      }
    },
    "/api/test-error/dependencies/smarty/http-error": {
      "get": {
        "tags": [
          "Diagnostics"
        ],
        "summary": "Exercises the Smarty address verification error path for a server-error HTTP response.\r\nSEBT.Portal.Infrastructure.Services.IAddressVerificationDiagnostics runs the real verification service against a\r\ncanned 500 response, so its `LogError` and `DependencyFailed` result are\r\nexercised without any network activity.",
        "responses": {
          "202": {
            "description": "Accepted"
          }
        }
      }
    },
    "/api/test-error/dependencies/smarty/transport-failure": {
      "get": {
        "tags": [
          "Diagnostics"
        ],
        "summary": "Exercises the Smarty address verification error path for a transport-level failure\r\n(e.g. firewall block, DNS failure). SEBT.Portal.Infrastructure.Services.IAddressVerificationDiagnostics simulates\r\nan System.Net.Http.HttpRequestException, which the verification service catches and logs\r\nat `Error`.",
        "responses": {
          "202": {
            "description": "Accepted"
          }
        }
      }
    },
    "/api/enrollment/check": {
      "post": {
        "tags": [
          "EnrollmentCheck"
        ],
        "summary": "Checks enrollment status for one or more children.\r\nThis is a public, unauthenticated endpoint.",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/EnrollmentCheckApiRequest"
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/EnrollmentCheckApiRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/EnrollmentCheckApiRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/EnrollmentCheckApiResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EnrollmentCheckApiResponse"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/EnrollmentCheckApiResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "429": {
            "description": "Too Many Requests",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        }
      }
    },
    "/api/enrollment/features": {
      "get": {
        "tags": [
          "EnrollmentCheck"
        ],
        "summary": "Returns runtime feature state for the standalone enrollment checker app\r\n(the maintenance banner toggle with its per-language copy, and the outage\r\npage state). This is a public, unauthenticated endpoint. In static-hosting\r\ndeployments (e.g. CO) the checker has no server of its own, so it polls this\r\nendpoint at runtime, which is what lets these be toggled via AWS AppConfig\r\nwithout a checker redeploy.",
        "responses": {
          "200": {
            "description": "Returns the current checker feature state.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EnrollmentCheckerFeaturesResponse"
                }
              }
            }
          },
          "429": {
            "description": "Too Many Requests",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        }
      }
    },
    "/api/features": {
      "get": {
        "tags": [
          "Features"
        ],
        "summary": "Gets the current feature flag states.\r\nReturns flags from state-specific JSON files (appsettings.{State}.json), AWS AppConfig (if configured), or defaults.\r\nFlags are merged in priority order with state-specific JSON having the highest priority.\r\nState-specific configuration is loaded from appsettings.{State}.json files based on the STATE environment variable.\r\nUnknown flags and internal-only flags (OTP bypass, diagnostic endpoints) are\r\nnot included in the response.",
        "responses": {
          "200": {
            "description": "Returns the current feature flag states.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {
                    "type": "boolean"
                  }
                }
              }
            }
          },
          "499": {
            "description": "The request was cancelled by the client.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "500": {
            "description": "An error occurred while retrieving feature flags."
          }
        }
      }
    },
    "/api/household/data": {
      "get": {
        "tags": [
          "Household"
        ],
        "summary": "Retrieves household data for the authenticated user.\r\nThe household identifier used for lookup is determined by state configuration (e.g. email, SNAP ID).\r\nPII data is only included when the user meets the ID proofing requirements configured for the state.",
        "parameters": [
          {
            "name": "includeCardDetails",
            "in": "query",
            "description": "When false, card-related fields are excluded from the response.",
            "schema": {
              "type": "boolean",
              "default": true
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Household data retrieved successfully. Returns empty arrays when no household is found for the authenticated user.",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/HouseholdDataResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HouseholdDataResponse"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/HouseholdDataResponse"
                }
              }
            }
          },
          "401": {
            "description": "User is not authorized or no household identifier could be resolved from token.",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "User's identity assurance level is below the minimum required by their cases.",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        }
      }
    },
    "/api/household/address": {
      "put": {
        "tags": [
          "Household"
        ],
        "summary": "Updates the mailing address for the authenticated user's household.\r\nReturns the address validation result, which may include a suggested alternative\r\n(e.g., abbreviated street name for DC) or a validation error (blocked address, too long).",
        "requestBody": {
          "description": "The new mailing address.",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateAddressRequest"
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateAddressRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateAddressRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Address validated and accepted.",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/AddressUpdateResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AddressUpdateResponse"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/AddressUpdateResponse"
                }
              }
            }
          },
          "400": {
            "description": "Input validation failed (missing fields, invalid format, or address could not be verified).",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "User is not authorized or no household identifier could be resolved from token.",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "422": {
            "description": "Address validation failed (blocked, too long, or has a suggested alternative).",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/AddressUpdateResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AddressUpdateResponse"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/AddressUpdateResponse"
                }
              }
            }
          },
          "502": {
            "description": "Address verification provider error or timeout.",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        }
      }
    },
    "/api/household/cards/replace": {
      "post": {
        "tags": [
          "Household"
        ],
        "summary": "Requests replacement cards for the authenticated user's household.",
        "requestBody": {
          "description": "The case IDs to request replacements for.",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RequestCardReplacementRequest"
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/RequestCardReplacementRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/RequestCardReplacementRequest"
              }
            }
          }
        },
        "responses": {
          "204": {
            "description": "Card replacement request recorded successfully."
          },
          "400": {
            "description": "Validation failed (no cases selected or cooldown active).",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "User is not authorized or no household identifier could be resolved from token.",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "Household data not found for the authenticated user.",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        }
      }
    },
    "/api/id-proofing": {
      "post": {
        "tags": [
          "IdProofing"
        ],
        "summary": "Submits ID proofing data for risk assessment.\r\nReturns whether the user matched, needs document verification, or failed.",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SubmitIdProofingRequest"
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/SubmitIdProofingRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/SubmitIdProofingRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Assessment completed. Check the result field for the outcome.",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/SubmitIdProofingResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SubmitIdProofingResponse"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/SubmitIdProofingResponse"
                }
              }
            }
          },
          "400": {
            "description": "Validation error in request data.",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "User is not authenticated.",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "User not found.",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/id-proofing/status": {
      "get": {
        "tags": [
          "IdProofing"
        ],
        "summary": "Gets the current verification status for a challenge.\r\nPolled by the frontend with exponential backoff after document capture.",
        "parameters": [
          {
            "name": "challengeId",
            "in": "query",
            "description": "The challenge's public GUID.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Status retrieved.",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/VerificationStatusResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/VerificationStatusResponse"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/VerificationStatusResponse"
                }
              }
            }
          },
          "401": {
            "description": "User is not authenticated.",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "Challenge not found or belongs to a different user.",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        }
      }
    },
    "/api/auth/oidc/{code}/config": {
      "get": {
        "tags": [
          "Oidc"
        ],
        "summary": "OIDC config + pre-auth session creation. Generates PKCE server-side, stores\r\n`state` + `code_verifier` + `stateCode` in the session store, sets an\r\n`oidc_session` HttpOnly cookie, and returns only the `code_challenge` +\r\n`state` to the browser. The `code_verifier` never leaves the server.",
        "description": "The authorization endpoint is intentionally NOT returned in this response.\r\nUse the `GET {code}/authorize` endpoint for server-side redirect instead.",
        "parameters": [
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "stepUp",
            "in": "query",
            "schema": {
              "type": "boolean",
              "default": false
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable"
          }
        }
      }
    },
    "/api/auth/oidc/{code}/authorize": {
      "get": {
        "tags": [
          "Oidc"
        ],
        "summary": "Server-side OIDC authorize redirect. Builds the full authorization URL on the server\r\nusing the `authorization_endpoint` from the IdP discovery document and returns a\r\n302 redirect.",
        "parameters": [
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "stepUp",
            "in": "query",
            "schema": {
              "type": "boolean",
              "default": false
            }
          },
          {
            "name": "returnUrl",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "language",
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "302": {
            "description": "Found"
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "502": {
            "description": "Bad Gateway"
          },
          "503": {
            "description": "Service Unavailable"
          }
        }
      }
    },
    "/api/auth/oidc/report-failure": {
      "post": {
        "tags": [
          "Oidc"
        ],
        "summary": "Records browser-only OIDC callback failures (IdP redirect `?error=` or missing\r\n`code`/`state`) before redirect to off-boarding. Failures from\r\n`POST callback` / `complete-login` are logged server-side only.",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/OidcCallbackFailureReportRequest"
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/OidcCallbackFailureReportRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/OidcCallbackFailureReportRequest"
              }
            }
          }
        },
        "responses": {
          "204": {
            "description": "No Content"
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/auth/oidc/callback": {
      "post": {
        "tags": [
          "Oidc"
        ],
        "summary": "Server-side OIDC callback. Requires the `oidc_session` cookie to\r\nlocate the pre-auth session; the orchestration (state validation, replay\r\nprotection, code exchange, session advancement) is dispatched to\r\nSEBT.Portal.UseCases.Auth.OidcCallback.OidcCallbackCommandHandler. The request body only needs\r\n`code` and `state`.",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/OidcCallbackRequest"
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/OidcCallbackRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/OidcCallbackRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK"
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable"
          }
        }
      }
    },
    "/api/auth/oidc/complete-login": {
      "post": {
        "tags": [
          "Oidc"
        ],
        "summary": "Completes OIDC login. Requires the `oidc_session` cookie to locate the\r\npre-auth session; the orchestration (callback-token verification, user\r\nresolution, portal JWT minting) is dispatched to\r\nSEBT.Portal.UseCases.Auth.CompleteOidcLogin.CompleteOidcLoginCommandHandler. On success the portal JWT is\r\nwritten to the session cookie and the pre-auth cookie is cleared. The request\r\nbody only needs `callbackToken`.",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CompleteLoginRequest"
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/CompleteLoginRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/CompleteLoginRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/CompleteLoginResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CompleteLoginResponse"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/CompleteLoginResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable"
          }
        }
      }
    },
    "/api/auth/otp/request": {
      "post": {
        "tags": [
          "Otp"
        ],
        "summary": "Request a one-time password (OTP) to be sent to the specified email address.",
        "requestBody": {
          "description": "The request containing the email address.",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RequestOtpApiRequest"
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/RequestOtpApiRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/RequestOtpApiRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "OTP requested successfully."
          },
          "400": {
            "description": "Invalid request.",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Maximum 5 OTP requests per minute allowed.",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        }
      }
    },
    "/api/auth/otp/validate": {
      "post": {
        "tags": [
          "Otp"
        ],
        "summary": "Validate a one-time password (OTP) for the specified email address.",
        "requestBody": {
          "description": "The request containing the email address and OTP code.",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ValidateOtpApiRequest"
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/ValidateOtpApiRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/ValidateOtpApiRequest"
              }
            }
          }
        },
        "responses": {
          "204": {
            "description": "OTP validated successfully. Session cookie set; no body."
          },
          "400": {
            "description": "Invalid OTP or request.",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Maximum 5 OTP requests per minute allowed.",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        }
      }
    },
    "/api/socure/webhook": {
      "post": {
        "tags": [
          "Webhook"
        ],
        "summary": "Receives a Socure evaluation_completed webhook.\r\nAlways returns 200 OK to prevent Socure retries, even if processing fails internally.",
        "requestBody": {
          "description": "The Socure webhook payload.",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookPayload"
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookPayload"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookPayload"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Webhook received and processed (or acknowledged)."
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "AddressResponse": {
        "type": "object",
        "properties": {
          "streetAddress1": {
            "type": "string",
            "description": "The street address line 1.",
            "nullable": true
          },
          "streetAddress2": {
            "type": "string",
            "description": "The street address line 2 (apartment, suite, etc.).",
            "nullable": true
          },
          "city": {
            "type": "string",
            "description": "The city.",
            "nullable": true
          },
          "state": {
            "type": "string",
            "description": "The state or province.",
            "nullable": true
          },
          "postalCode": {
            "type": "string",
            "description": "The postal or ZIP code.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "API response model for an address on file."
      },
      "AddressUpdateResponse": {
        "required": [
          "status"
        ],
        "type": "object",
        "properties": {
          "status": {
            "type": "string",
            "description": "The validation status: \"valid\", \"invalid\", or \"suggestion\".",
            "nullable": true
          },
          "reason": {
            "type": "string",
            "description": "The specific reason for the validation outcome (e.g., \"blocked\", \"too_long\", \"abbreviated\").",
            "nullable": true
          },
          "message": {
            "type": "string",
            "description": "A user-facing error message when the address is invalid.",
            "nullable": true
          },
          "normalizedAddress": {
            "$ref": "#/components/schemas/AddressResponse"
          },
          "suggestedAddress": {
            "$ref": "#/components/schemas/AddressResponse"
          }
        },
        "additionalProperties": false,
        "description": "API response for an address update request, including the validation outcome."
      },
      "AllowedActionsResponse": {
        "type": "object",
        "properties": {
          "canUpdateAddress": {
            "type": "boolean",
            "description": "Whether the user can update their mailing address via the portal."
          },
          "canRequestReplacementCard": {
            "type": "boolean",
            "description": "Whether the user can request a replacement card via the portal."
          },
          "addressUpdateDeniedMessageKey": {
            "type": "string",
            "description": "i18n key for the message shown when address update is denied.",
            "nullable": true
          },
          "cardReplacementDeniedMessageKey": {
            "type": "string",
            "description": "i18n key for the message shown when card replacement is denied.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "API response model for computed self-service action permissions."
      },
      "ApplicationResponse": {
        "type": "object",
        "properties": {
          "applicationNumber": {
            "type": "string",
            "description": "The application number.",
            "nullable": true
          },
          "caseNumber": {
            "type": "string",
            "description": "The case number associated with this application.",
            "nullable": true
          },
          "applicationStatus": {
            "$ref": "#/components/schemas/ApplicationStatus"
          },
          "applicationDate": {
            "type": "string",
            "description": "The date the application was submitted.",
            "format": "date-time",
            "nullable": true
          },
          "benefitIssueDate": {
            "type": "string",
            "description": "The date when the benefit was issued for this application.",
            "format": "date-time",
            "nullable": true
          },
          "benefitExpirationDate": {
            "type": "string",
            "description": "The date when the benefit expires for this application.",
            "format": "date-time",
            "nullable": true
          },
          "children": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ChildResponse"
            },
            "description": "The list of children on this application.",
            "nullable": true
          },
          "childrenOnApplication": {
            "type": "integer",
            "description": "The number of children on this application.",
            "format": "int32"
          },
          "issuanceType": {
            "$ref": "#/components/schemas/IssuanceType"
          }
        },
        "additionalProperties": false,
        "description": "API response model for a benefit application."
      },
      "ApplicationStatus": {
        "enum": [
          0,
          1,
          2,
          3,
          4,
          5
        ],
        "type": "integer",
        "format": "int32"
      },
      "ApplyFeature": {
        "type": "object",
        "properties": {
          "enabled": {
            "type": "boolean",
            "description": "Whether applications are open."
          }
        },
        "additionalProperties": false,
        "description": "Application window state for the enrollment checker."
      },
      "AuthorizationStatusResponse": {
        "type": "object",
        "properties": {
          "isAuthorized": {
            "type": "boolean",
            "description": "True when the caller has a valid session; false for anonymous callers (no cookie, or an\r\nexpired/tampered/revoked session), in which case all other fields are null."
          },
          "userId": {
            "type": "string",
            "description": "Stable, non-PII portal user identifier (the portal's own user UUID). Surfaced for\r\nanalytics so events can be correlated per-user across page loads without exposing\r\nemail or other PII to vendor tooling. Null when the claim is absent.",
            "format": "uuid",
            "nullable": true
          },
          "email": {
            "type": "string",
            "description": "The email address of the signed-in user. Null for anonymous callers, and null when\r\nthe claim is absent from the session.",
            "nullable": true
          },
          "ial": {
            "type": "string",
            "description": "Identity assurance level claim from the JWT (\"0\", \"1\", \"1plus\", or \"2\"). Null when unknown.",
            "nullable": true
          },
          "idProofingStatus": {
            "type": "integer",
            "description": "Workflow state of the user's ID proofing process. See `SEBT.Portal.Core.Models.Auth.IdProofingStatus`.\r\nNull when the claim is absent.",
            "format": "int32",
            "nullable": true
          },
          "idProofingCompletedAt": {
            "type": "integer",
            "description": "Unix seconds timestamp of the most recent successful ID proofing completion. Null when none.",
            "format": "int64",
            "nullable": true
          },
          "idProofingExpiresAt": {
            "type": "integer",
            "description": "Unix seconds timestamp after which the IdP-bounded proofing credential should be re-verified. Null when not time-bounded.",
            "format": "int64",
            "nullable": true
          },
          "isCoLoaded": {
            "type": "boolean",
            "description": "Whether the user's record was co-loaded from an external state system. Null when the claim is absent.",
            "nullable": true
          },
          "expiresAt": {
            "type": "integer",
            "description": "Unix seconds timestamp at which the current session cookie expires (sliding/idle expiry).\r\nThe SPA uses this to schedule activity-gated refreshes. Null when the claim is absent.",
            "format": "int64",
            "nullable": true
          },
          "absoluteExpiresAt": {
            "type": "integer",
            "description": "Unix seconds timestamp at which the session reaches its absolute lifetime cap, regardless of\r\nactivity. Computed from the JWT `auth_time` claim plus `JwtSettings.AbsoluteExpirationMinutes`.\r\nNull when `auth_time` is absent.",
            "format": "int64",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Response model for GET /api/auth/status. Carries non-sensitive session claims the SPA\r\nneeds to drive UI decisions (IAL gating, analytics) now that the raw JWT lives in an\r\nHttpOnly cookie and cannot be decoded client-side. Anonymous callers get this same\r\nshape with `IsAuthorized` false and every claim null."
      },
      "BenefitExpirationStatus": {
        "enum": [
          "Expiring",
          "Expired"
        ],
        "type": "string"
      },
      "BenefitIssuanceType": {
        "enum": [
          0,
          1,
          2,
          3
        ],
        "type": "integer",
        "format": "int32"
      },
      "CardStatus": {
        "enum": [
          "Active",
          "Damaged",
          "DeactivatedByState",
          "Frozen",
          "Lost",
          "NotActivated",
          "Processed",
          "Stolen",
          "Undeliverable",
          "Unknown"
        ],
        "type": "string"
      },
      "CaseRefRequestDto": {
        "required": [
          "summerEbtCaseId"
        ],
        "type": "object",
        "properties": {
          "summerEbtCaseId": {
            "minLength": 1,
            "type": "string",
            "description": "Primary case identifier (from `SummerEbtCase.summerEBTCaseID`)."
          },
          "applicationId": {
            "type": "string",
            "description": "Application identifier when the case is application-based; null for auto-eligible cases.",
            "nullable": true
          },
          "applicationStudentId": {
            "type": "string",
            "description": "Per-(case, child) identifier when the case is application-based; null for auto-eligible cases.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Wire shape of a single case reference. Mirrors the use-cases `CaseRefDto`\r\nand the state-connector `CaseRef`."
      },
      "ChildCheckApiRequest": {
        "type": "object",
        "properties": {
          "firstName": {
            "type": "string",
            "description": "Child's first name.",
            "nullable": true
          },
          "lastName": {
            "type": "string",
            "description": "Child's last name.",
            "nullable": true
          },
          "dateOfBirth": {
            "type": "string",
            "description": "Child's date of birth in yyyy-MM-dd format.",
            "nullable": true
          },
          "schoolName": {
            "type": "string",
            "description": "Name of the child's school (optional).",
            "nullable": true
          },
          "schoolCode": {
            "type": "string",
            "description": "Code identifying the child's school (optional).",
            "nullable": true
          },
          "additionalFields": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            },
            "description": "State-specific additional fields (optional).",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Individual child data for an enrollment check request."
      },
      "ChildCheckApiResponse": {
        "type": "object",
        "properties": {
          "checkId": {
            "type": "string",
            "description": "Unique identifier for this check result.",
            "nullable": true
          },
          "firstName": {
            "type": "string",
            "description": "Child's first name.",
            "nullable": true
          },
          "lastName": {
            "type": "string",
            "description": "Child's last name.",
            "nullable": true
          },
          "dateOfBirth": {
            "type": "string",
            "description": "Child's date of birth in yyyy-MM-dd format.",
            "nullable": true
          },
          "status": {
            "type": "string",
            "description": "Enrollment status (Match, PossibleMatch, NonMatch, Error).",
            "nullable": true
          },
          "matchConfidence": {
            "type": "number",
            "description": "Confidence score for the match, if applicable.",
            "format": "double",
            "nullable": true
          },
          "eligibilityType": {
            "type": "string",
            "description": "Type of eligibility (Snap, Tanf, Frp, DirectCert), if matched.",
            "nullable": true
          },
          "schoolName": {
            "type": "string",
            "description": "Name of the school associated with the enrollment record.",
            "nullable": true
          },
          "statusMessage": {
            "type": "string",
            "description": "Human-readable status message with additional details.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Individual child enrollment check result."
      },
      "ChildResponse": {
        "type": "object",
        "properties": {
          "firstName": {
            "type": "string",
            "description": "The child's first name.",
            "nullable": true
          },
          "lastName": {
            "type": "string",
            "description": "The child's last name.",
            "nullable": true
          },
          "status": {
            "$ref": "#/components/schemas/ApplicationStatus"
          }
        },
        "additionalProperties": false,
        "description": "API response model for a child on a benefit application."
      },
      "CoLoadedCohort": {
        "enum": [
          0,
          1,
          2
        ],
        "type": "integer",
        "format": "int32"
      },
      "CompleteLoginRequest": {
        "type": "object",
        "properties": {
          "stateCode": {
            "type": "string",
            "nullable": true
          },
          "callbackToken": {
            "type": "string",
            "nullable": true
          },
          "isStepUp": {
            "type": "boolean"
          },
          "returnUrl": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Request body for completing OIDC login after the Next.js server has exchanged the code and validated the id_token.\r\nCallbackToken is a short-lived JWT signed by the Next.js app (OIDC_COMPLETE_LOGIN_SIGNING_KEY) containing the IdP claims.\r\nWhen IsStepUp is true, updates the user's IAL level and ID proofing status instead of creating a new session.\r\nWhen set, `returnUrl` must be a safe relative path (starts with `/`, not `//`, no scheme). Otherwise it is ignored."
      },
      "CompleteLoginResponse": {
        "type": "object",
        "properties": {
          "returnUrl": {
            "type": "string",
            "description": "For OIDC step-up flows, the relative path the user should be redirected to after verification succeeds.\r\nNull for normal login — caller should redirect to the dashboard.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Response body for POST /api/auth/oidc/complete-login.\r\nThe portal JWT is returned via an HttpOnly cookie (see `AuthCookies`) — never in the response body."
      },
      "DateOfBirthDto": {
        "type": "object",
        "properties": {
          "month": {
            "type": "string",
            "nullable": true
          },
          "day": {
            "type": "string",
            "nullable": true
          },
          "year": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Structured date-of-birth as sent by the frontend form.\r\nEach component is zero-padded (e.g. month \"03\", day \"15\", year \"1990\")."
      },
      "EnrollmentCheckApiRequest": {
        "type": "object",
        "properties": {
          "children": {
            "maxItems": 20,
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ChildCheckApiRequest"
            },
            "description": "The children to check enrollment for.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Request model for checking enrollment status of one or more children."
      },
      "EnrollmentCheckApiResponse": {
        "type": "object",
        "properties": {
          "results": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ChildCheckApiResponse"
            },
            "description": "Results for each child checked.",
            "nullable": true
          },
          "message": {
            "type": "string",
            "description": "Optional message from the enrollment check service.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Response model for enrollment check results."
      },
      "EnrollmentCheckerFeaturesResponse": {
        "type": "object",
        "properties": {
          "maintenanceBanner": {
            "$ref": "#/components/schemas/MaintenanceBannerFeature"
          },
          "outagePage": {
            "$ref": "#/components/schemas/OutagePageFeature"
          },
          "incomeEligibility": {
            "$ref": "#/components/schemas/IncomeEligibilityFeature"
          },
          "apply": {
            "$ref": "#/components/schemas/ApplyFeature"
          },
          "enrollment": {
            "$ref": "#/components/schemas/EnrollmentFeature"
          }
        },
        "additionalProperties": false,
        "description": "Runtime feature state for the standalone enrollment checker app.\r\nServed unauthenticated so the statically-hosted checker can poll it at runtime."
      },
      "EnrollmentFeature": {
        "type": "object",
        "properties": {
          "enabled": {
            "type": "boolean",
            "description": "Whether the season is still enrolling. False switches the checker to past-tense copy."
          }
        },
        "additionalProperties": false,
        "description": "Season state for the enrollment checker."
      },
      "ErrorResponse": {
        "type": "object",
        "properties": {
          "error": {
            "type": "string",
            "description": "The error message.",
            "nullable": true
          },
          "errors": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ValidationError"
            },
            "description": "Optional collection of validation errors, if applicable.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Standard error response model for API error responses."
      },
      "HouseholdDataResponse": {
        "type": "object",
        "properties": {
          "email": {
            "type": "string",
            "description": "The email address on file for the household.\r\nNull when excluded due to ID proofing requirements.",
            "nullable": true
          },
          "phone": {
            "type": "string",
            "description": "The phone number on file for the household.",
            "nullable": true
          },
          "summerEbtCases": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SummerEbtCaseResponse"
            },
            "description": "The list of Summer EBT cases (per-child) for this household.",
            "nullable": true
          },
          "applications": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ApplicationResponse"
            },
            "description": "The list of applications for this household.",
            "nullable": true
          },
          "addressOnFile": {
            "$ref": "#/components/schemas/AddressResponse"
          },
          "userProfile": {
            "$ref": "#/components/schemas/UserProfileResponse"
          },
          "benefitIssuanceType": {
            "$ref": "#/components/schemas/BenefitIssuanceType"
          },
          "allowedActions": {
            "$ref": "#/components/schemas/AllowedActionsResponse"
          },
          "coLoadedCohort": {
            "$ref": "#/components/schemas/CoLoadedCohort"
          },
          "hashedAppId": {
            "type": "string",
            "description": "HMAC-SHA256 digest of the SEBT App ID, lowercase hex. Surfaced for\r\nanalytics so CO/CfA can join vendor exports (Mixpanel/Amplitude) back\r\nto state program data via a shared deterministic hash without\r\nexposing raw identifiers. Populated only when the active state is\r\nconfigured to emit it (CO today) and an App ID exists for the\r\nhousehold; null otherwise. See docs/analytics/hashed-sebt-app-id.md.",
            "nullable": true
          },
          "hashedAppIds": {
            "type": "string",
            "description": "Sorted, comma-joined 16-character digest prefixes of every state application id in the\r\nhousehold, including directly certified children's. Gated like SEBT.Portal.Api.Models.Household.HouseholdDataResponse.HashedAppId.",
            "nullable": true
          },
          "hashedCaseIds": {
            "type": "string",
            "description": "Sorted, comma-joined 16-character digest prefixes of every child's state case id, including\r\nchildren known only through a pending application. Gated like SEBT.Portal.Api.Models.Household.HouseholdDataResponse.HashedAppId.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "API response model for household data."
      },
      "IncomeEligibilityFeature": {
        "type": "object",
        "properties": {
          "baseThreshold": {
            "type": "number",
            "description": "Annual gross income threshold for a household of one.",
            "format": "double"
          },
          "perMemberIncrement": {
            "type": "number",
            "description": "Added to the threshold for each household member beyond the first.",
            "format": "double"
          },
          "maxHouseholdSize": {
            "type": "integer",
            "description": "Largest household size the selector offers.",
            "format": "int32"
          }
        },
        "additionalProperties": false,
        "description": "Income screening thresholds for the checker's not-enrolled result. The threshold is\r\nSEBT.Portal.Api.Models.EnrollmentCheck.IncomeEligibilityFeature.BaseThreshold plus SEBT.Portal.Api.Models.EnrollmentCheck.IncomeEligibilityFeature.PerMemberIncrement per member beyond\r\nthe first."
      },
      "IssuanceType": {
        "enum": [
          0,
          1,
          2,
          3
        ],
        "type": "integer",
        "format": "int32"
      },
      "MaintenanceBannerFeature": {
        "type": "object",
        "properties": {
          "enabled": {
            "type": "boolean",
            "description": "Whether the maintenance banner should be shown."
          },
          "message": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            },
            "description": "Per-language banner copy, keyed by lowercase ISO language code (e.g. \"en\", \"es\").\r\nThe checker picks the active language client-side.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Maintenance banner state for the enrollment checker."
      },
      "OidcCallbackFailureReportRequest": {
        "type": "object",
        "properties": {
          "reason": {
            "type": "string",
            "nullable": true
          },
          "idpError": {
            "type": "string",
            "nullable": true
          },
          "idpErrorDescription": {
            "type": "string",
            "nullable": true
          },
          "httpStatus": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "apiError": {
            "type": "string",
            "nullable": true
          },
          "phase": {
            "type": "string",
            "nullable": true
          },
          "hasCode": {
            "type": "boolean",
            "nullable": true
          },
          "hasState": {
            "type": "boolean",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Browser-reported OIDC callback failure (IdP redirect errors and missing OAuth params)\r\nfor server-side logging before redirect to off-boarding. Exchange and complete-login\r\nfailures are logged on the server only."
      },
      "OidcCallbackRequest": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "nullable": true
          },
          "state": {
            "type": "string",
            "nullable": true
          },
          "stateCode": {
            "type": "string",
            "nullable": true
          },
          "isStepUp": {
            "type": "boolean"
          }
        },
        "additionalProperties": false,
        "description": "request body for the server-side OIDC callback endpoint.\r\nThe `code_verifier` and `redirect_uri` are never accepted from the\r\nclient — they are read from the pre-auth session stored server-side. The browser\r\nonly sends the authorization code and metadata needed to match the session."
      },
      "OutagePageFeature": {
        "type": "object",
        "properties": {
          "enabled": {
            "type": "boolean",
            "description": "Whether the outage page should be shown."
          }
        },
        "additionalProperties": false,
        "description": "Outage page state for the enrollment checker. When enabled, the checker replaces all\r\nroutes with a full-page outage notice."
      },
      "ProblemDetails": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "nullable": true
          },
          "title": {
            "type": "string",
            "nullable": true
          },
          "status": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "detail": {
            "type": "string",
            "nullable": true
          },
          "instance": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": { }
      },
      "RequestCardReplacementRequest": {
        "required": [
          "caseRefs"
        ],
        "type": "object",
        "properties": {
          "caseRefs": {
            "minItems": 1,
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CaseRefRequestDto"
            },
            "description": "Case references identifying which cards to replace."
          }
        },
        "additionalProperties": false,
        "description": "Request model for requesting replacement cards for one or more cases."
      },
      "RequestOtpApiRequest": {
        "type": "object",
        "properties": {
          "email": {
            "type": "string",
            "nullable": true
          },
          "locale": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Request body for requesting a one-time password (OTP) to be sent to an email address."
      },
      "ResubmitChallengeResponse": {
        "type": "object",
        "properties": {
          "challengeId": {
            "type": "string",
            "format": "uuid"
          },
          "docvTransactionToken": {
            "type": "string",
            "nullable": true
          },
          "docvUrl": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "StartChallengeResponse": {
        "type": "object",
        "properties": {
          "docvTransactionToken": {
            "type": "string",
            "nullable": true
          },
          "docvUrl": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "SubmitIdProofingRequest": {
        "type": "object",
        "properties": {
          "dateOfBirth": {
            "$ref": "#/components/schemas/DateOfBirthDto"
          },
          "idType": {
            "type": "string",
            "nullable": true
          },
          "idValue": {
            "type": "string",
            "nullable": true
          },
          "diSessionToken": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Request body for POST /api/id-proofing.\r\nMaps the frontend form submission to the use case command."
      },
      "SubmitIdProofingResponse": {
        "type": "object",
        "properties": {
          "result": {
            "type": "string",
            "nullable": true
          },
          "challengeId": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "allowIdRetry": {
            "type": "boolean",
            "nullable": true
          },
          "canApply": {
            "type": "boolean",
            "nullable": true
          },
          "offboardingReason": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "SummerEbtCaseResponse": {
        "type": "object",
        "properties": {
          "summerEBTCaseID": {
            "type": "string",
            "description": "The Summer EBT case identifier.",
            "nullable": true
          },
          "applicationId": {
            "type": "string",
            "description": "The application ID for this case.",
            "nullable": true
          },
          "applicationStudentId": {
            "type": "string",
            "description": "The application student ID.",
            "nullable": true
          },
          "childFirstName": {
            "type": "string",
            "description": "The child's first name.",
            "nullable": true
          },
          "childLastName": {
            "type": "string",
            "description": "The child's last name.",
            "nullable": true
          },
          "childDateOfBirth": {
            "type": "string",
            "description": "The child's date of birth.",
            "format": "date-time",
            "nullable": true
          },
          "householdType": {
            "type": "string",
            "description": "The household type.",
            "nullable": true
          },
          "eligibilityType": {
            "type": "string",
            "description": "The eligibility type.",
            "nullable": true
          },
          "eligibilitySource": {
            "type": "string",
            "description": "The source of eligibility (e.g. school, SNAP, TANF).",
            "nullable": true
          },
          "issuanceType": {
            "$ref": "#/components/schemas/IssuanceType"
          },
          "applicationDate": {
            "type": "string",
            "description": "The application date.",
            "format": "date-time",
            "nullable": true
          },
          "applicationStatus": {
            "$ref": "#/components/schemas/ApplicationStatus"
          },
          "mailingAddress": {
            "$ref": "#/components/schemas/AddressResponse"
          },
          "ebtCaseNumber": {
            "type": "string",
            "description": "State backend case identifier when exposed by the connector (e.g. CBMS case id).",
            "nullable": true
          },
          "caseDisplayNumber": {
            "type": "string",
            "description": "Guardian-facing reference when distinct from SEBT.Portal.Api.Models.Household.SummerEbtCaseResponse.EbtCaseNumber (e.g. Colorado application id).",
            "nullable": true
          },
          "ebtCardLastFour": {
            "type": "string",
            "description": "The last 4 digits of the EBT card.",
            "nullable": true
          },
          "ebtCardStatus": {
            "$ref": "#/components/schemas/CardStatus"
          },
          "ebtCardIssueDate": {
            "type": "string",
            "description": "The EBT card issue date.",
            "format": "date-time",
            "nullable": true
          },
          "ebtCardBalance": {
            "type": "number",
            "description": "The EBT card balance.",
            "format": "double",
            "nullable": true
          },
          "cardRequestedAt": {
            "type": "string",
            "description": "When a card replacement was last requested for this case.",
            "format": "date-time",
            "nullable": true
          },
          "benefitAvailableDate": {
            "type": "string",
            "description": "The date benefits become available.",
            "format": "date-time",
            "nullable": true
          },
          "benefitExpirationDate": {
            "type": "string",
            "description": "The date benefits expire.",
            "format": "date-time",
            "nullable": true
          },
          "benefitExpirationStatus": {
            "$ref": "#/components/schemas/BenefitExpirationStatus"
          },
          "allowAddressChange": {
            "type": "boolean",
            "description": "Whether the portal user can change the mailing address for this case.\r\nFalse for co-loaded cases (benefits managed by caseworker)."
          },
          "allowCardReplacement": {
            "type": "boolean",
            "description": "Whether the portal user can request a replacement card for this case.\r\nFalse for co-loaded cases (benefits managed by caseworker)."
          }
        },
        "additionalProperties": false,
        "description": "API response model for a Summer EBT case (per-child)."
      },
      "UpdateAddressRequest": {
        "required": [
          "city",
          "postalCode",
          "state",
          "streetAddress1"
        ],
        "type": "object",
        "properties": {
          "streetAddress1": {
            "minLength": 1,
            "type": "string",
            "description": "Street address line 1 (e.g., \"123 Main St NW\")."
          },
          "streetAddress2": {
            "type": "string",
            "description": "Street address line 2 (e.g., apartment, suite). Optional.",
            "nullable": true
          },
          "city": {
            "minLength": 1,
            "type": "string",
            "description": "City name."
          },
          "state": {
            "minLength": 1,
            "type": "string",
            "description": "State or territory name."
          },
          "postalCode": {
            "minLength": 1,
            "pattern": "^\\d{5}(-\\d{4})?$",
            "type": "string",
            "description": "5- or 9-digit ZIP code (e.g., \"20001\" or \"20001-1234\")."
          },
          "acceptEnteredAddress": {
            "type": "boolean",
            "description": "Persist the submitted address even when verification suggests an alternative (user chose entered address).",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Request model for updating a household's mailing address."
      },
      "UserProfileResponse": {
        "type": "object",
        "properties": {
          "firstName": {
            "type": "string",
            "description": "The user's first name.",
            "nullable": true
          },
          "middleName": {
            "type": "string",
            "description": "The user's middle name, if any.",
            "nullable": true
          },
          "lastName": {
            "type": "string",
            "description": "The user's last name.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "API response model for the logged-in user's profile name"
      },
      "ValidateOtpApiRequest": {
        "type": "object",
        "properties": {
          "email": {
            "type": "string",
            "nullable": true
          },
          "otp": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Request body for validating a one-time password (OTP) for user authentication."
      },
      "ValidationError": {
        "type": "object",
        "properties": {
          "key": {
            "type": "string",
            "nullable": true
          },
          "message": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "ValidationProblemDetails": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "nullable": true
          },
          "title": {
            "type": "string",
            "nullable": true
          },
          "status": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "detail": {
            "type": "string",
            "nullable": true
          },
          "instance": {
            "type": "string",
            "nullable": true
          },
          "errors": {
            "type": "object",
            "additionalProperties": {
              "type": "array",
              "items": {
                "type": "string"
              }
            },
            "nullable": true
          }
        },
        "additionalProperties": { }
      },
      "VerificationStatusResponse": {
        "type": "object",
        "properties": {
          "status": {
            "type": "string",
            "nullable": true
          },
          "allowIdRetry": {
            "type": "boolean",
            "nullable": true
          },
          "offboardingReason": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "WebhookData": {
        "type": "object",
        "properties": {
          "eval_id": {
            "type": "string",
            "description": "Socure evaluation ID for challenge correlation (fallback key).",
            "nullable": true
          },
          "decision": {
            "type": "string",
            "description": "Top-level decision from the evaluation (e.g., \"accept\", \"reject\", \"review\").",
            "nullable": true
          },
          "data_enrichments": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/WebhookDataEnrichment"
            },
            "description": "Array of enrichment results from the evaluation pipeline.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Nested data object within the Socure webhook payload.\r\nContains the evaluation result and data enrichments."
      },
      "WebhookDataEnrichment": {
        "type": "object",
        "properties": {
          "enrichment_name": {
            "type": "string",
            "description": "Name of the enrichment (e.g., \"SocureDocRequest\").",
            "nullable": true
          },
          "enrichment_provider": {
            "type": "string",
            "description": "Provider of the enrichment (e.g., \"SocureDocRequest\", \"Socure\").",
            "nullable": true
          },
          "status_code": {
            "type": "integer",
            "description": "HTTP status code from the enrichment provider.",
            "format": "int32"
          },
          "response": {
            "description": "Enrichment-specific response data. Shape varies by provider.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "A single enrichment result from the Socure evaluation pipeline.\r\nEach enrichment has a different response shape — parsed via System.Text.Json.JsonElement."
      },
      "WebhookPayload": {
        "type": "object",
        "properties": {
          "event_id": {
            "type": "string",
            "description": "Socure event identifier for idempotency.",
            "nullable": true
          },
          "event_at": {
            "type": "string",
            "description": "Timestamp of the event.",
            "nullable": true
          },
          "event_type": {
            "type": "string",
            "description": "Event type (e.g., \"evaluation_completed\").",
            "nullable": true
          },
          "data": {
            "$ref": "#/components/schemas/WebhookData"
          }
        },
        "additionalProperties": false,
        "description": "Incoming Socure webhook payload for evaluation events.\r\nMatches the real Socure webhook structure from the OpenAPI spec."
      }
    }
  }
}