openapi: 3.0.3 info: title: BFF - CED Application Management (INPS Cooperation) description: | Backend For Frontend (BFF) API for managing the CED application process. The BFF handles all state transitions, idempotency logic (retrieving/generating the Idempotency Key internally), and reconciliation with INPS. The Codice Fiscale (CF) is retrieved from the user's session. All endpoints are protected by an opaque token in the Authorization header. version: 1.0.0 servers: - url: https://api.your-bff.it/v1 description: BFF production endpoint security: - BearerAuth: [] tags: - name: Access description: Authentication flow via FIMS (OIDC). Obtain a session token before calling protected endpoints. - name: Status Check and Reconciliation description: Status retrieval and reconciliation of the local state against the INPS source of truth (CheckDomanda). - name: Application Creation description: New application draft submission (NuovaDomandaInBozza). - name: Photo Upload description: Passport photo submission (FornisciFoto). - name: Confirmation and Documentation description: Final confirmation with optional documentation (ConfermaDomanda). - name: Read-Only Operations description: Read-only proxies to INPS (RecuperoDatiDomanda, RichiediRiepilogo, RichiediRicevuta, RichiediStato). Ownership of the idLavorazione is verified against the session before proxying. paths: /fauth: get: tags: - Access summary: Initiate FIMS authentication description: | Starts the OIDC/FIMS authentication flow. Redirects the user-agent to the identity provider. operationId: fimsAuth security: [] responses: "302": description: Redirect to the OpenID Connect provider. "500": description: Internal server error. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /fcb: get: tags: - Access summary: FIMS callback description: | Callback endpoint called by the identity provider after authentication. Validates the OIDC response, creates a session, and redirects the frontend to `/authorize` with a short-lived `id` parameter. operationId: fimsCallback security: [] parameters: - in: query name: state required: true schema: type: string - in: query name: code required: true schema: type: string - in: query name: iss required: true schema: type: string - in: header name: signature required: false schema: type: string - in: header name: signature-input required: false schema: type: string responses: "302": description: Redirect to `/authorize` with the session `id` in the query parameters. "401": description: Unauthorized — invalid or expired OIDC response. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "500": description: Internal server error. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /authorize: get: tags: - Access summary: Exchange session id for a session token description: | Called by the frontend after being redirected from `/fcb`. Exchanges the short-lived `id` for a durable session token that must be used to authenticate all subsequent requests to protected endpoints. operationId: authorize security: [] parameters: - in: query name: id required: true schema: type: string responses: "200": description: Session token successfully issued. content: application/json: schema: type: object required: - token properties: token: type: string "401": description: Unauthorized — invalid or expired session id. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "500": description: Internal server error. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /status: get: tags: - Status Check and Reconciliation summary: Retrieves the current application state (and initiates reconciliation) description: | Called upon user access or retry. Executes the INPS CheckDomanda call in the background, reconciles the local DB state, and returns the current stable state required for the FE to direct the user flow. operationId: getApplicationStatus responses: "200": description: Application status determined (reconciled) content: application/json: schema: type: object properties: state: $ref: "#/components/schemas/ApplicationState" description: Current or final application state. idLavorazione: type: string nullable: true description: INPS idLavorazione bound to the application, when one exists. numDomus: type: string description: INPS-assigned document number, present when state is ACQUIRED. "401": description: Unauthorized — invalid or expired session. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "400": description: INPS business/logic error (e.g., Active Card, foreign residence, Codes 700, 212-214) content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "500": description: BFF or INPS internal error (e.g., Code 100) content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "503": description: Critical DB service unavailable (Failure to read local state) content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /request: post: tags: - Application Creation summary: Submits data for a new application draft (NuovaDomandaInBozza) description: | Invoked when the status is READY_FOR_NEW_DRAFT (or to replace an existing draft). The client supplies an `Idempotency-Key` identifying the user action: re-sending the same key is a safe retry, while a new key replaces the current draft (INPS cancels it and issues a new idLavorazione, invalidating any previously uploaded photo/documents). operationId: createNewApplication parameters: - $ref: "#/components/parameters/IdempotencyKey" requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/NuovaDomandaInBozzaRequest" responses: "200": description: Application saved as draft. Next state returned. content: application/json: schema: type: object properties: state: $ref: "#/components/schemas/ApplicationState" example: READY_FOR_PHOTO_UPLOAD idLavorazione: type: string description: INPS idLavorazione associated with the application maxLength: 20 "401": description: Unauthorized — invalid or expired session. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "400": description: INPS data validation error (Codes 200-315) content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "500": description: BFF or INPS internal error (Code 100) content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "503": description: Critical DB error during the first local save (DRAFT state) content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /image: post: tags: - Photo Upload summary: Uploads the passport photo (FornisciFoto) description: | Invoked when the state is READY_FOR_PHOTO_UPLOAD. The client supplies an `Idempotency-Key` identifying the user action: re-sending the same key is a safe retry, while a new key overwrites the previously associated photo. operationId: uploadPhoto parameters: - $ref: "#/components/parameters/IdempotencyKey" requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/FornisciFotoRequest" responses: "200": description: Photo acquired and validated. Next state returned. content: application/json: schema: $ref: "#/components/schemas/StateResponse" properties: state: $ref: "#/components/schemas/ApplicationState" example: READY_FOR_DOCUMENTS_UPLOAD "401": description: Unauthorized — invalid or expired session. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "400": description: Photo validation or state inconsistency error (Codes 900-911, 115) content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "500": description: BFF or INPS internal error (Code 100) content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "503": description: Critical DB error during the first local save (UPLOADING_PHOTO) content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /confirm: post: tags: - Confirmation and Documentation summary: Final confirmation of the application (ConfermaDomanda) description: | Invoked when the state is READY_FOR_DOCUMENTS_UPLOAD. The client supplies an `Idempotency-Key` identifying the user action: re-sending the same key is a safe retry. Once the application is ACQUIRED, a different key yields `400 / 115` (state not coherent). operationId: confirmApplication parameters: - $ref: "#/components/parameters/IdempotencyKey" requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/ConfermaDomandaRequest" responses: "200": description: Application acquired by INPS. Final state returned. content: application/json: schema: type: object properties: state: $ref: "#/components/schemas/ApplicationState" example: ACQUIRED numDomus: type: string nullable: true description: INPS-assigned document number for the acquired application. "401": description: Unauthorized — invalid or expired session. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "400": description: Documentation validation or state inconsistency error (Codes 400-409, 114, 115) content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "500": description: BFF or INPS internal error (Code 100) content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "503": description: Critical DB error during the first local save (UPLOADING_DOCUMENTS) content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /draft: get: tags: - Read-Only Operations summary: Retrieves the saved draft data (RecuperoDatiDomanda) description: | Proxies INPS `RecuperoDatiDomanda`. Returns the data of the AppIO draft when `CheckDomanda` returns `esitoCheck` 20 (draft without photo) or 30 (draft with photo). The photo is returned in Base64 only for status 30. The frontend must call `GET /status` first. The BFF reads the reconciled state and active `idLavorazione` from the CosmosDB support record, then proxies the recovery request without calling `CheckDomanda` again. This endpoint restores and pre-fills an interrupted card request flow. operationId: getDraftData responses: "200": description: Draft data retrieved. content: application/json: schema: $ref: "#/components/schemas/DraftDataResponse" "400": description: INPS validation / state error (Codes 100-115) content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "404": description: No reconciled support record or draft associated with the session. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "500": description: BFF or INPS internal error (Code 100) content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "503": description: Critical DB service unavailable (failure to read local state) content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /details: get: tags: - Read-Only Operations summary: Retrieves the application/card status detail (RichiediStato) description: | Proxies INPS `RichiediStato`. Returns the detailed state of the application and, if present, of the card. Available whenever an application exists (esitoCheck 40 or 50). The BFF verifies idLavorazione ownership before proxying. operationId: getApplicationDetails responses: "200": description: Status detail retrieved. content: application/json: schema: $ref: "#/components/schemas/StatusDetailResponse" "400": description: INPS validation error (Codes 100-112) content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "404": description: No application associated with the session. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "500": description: BFF or INPS internal error (Code 100) content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "503": description: Critical DB service unavailable (failure to read local state) content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /summary: get: tags: - Read-Only Operations summary: Retrieves the application summary PDF (RichiediRiepilogo) description: | Proxies INPS `RichiediRiepilogo`. Returns the summary PDF of the submitted application, available only from state ACQUISITA (30). The BFF verifies idLavorazione ownership before proxying. operationId: getApplicationSummary responses: "200": description: Summary PDF available. content: application/json: schema: $ref: "#/components/schemas/PdfDocumentResponse" "400": description: INPS validation / state error (Codes 100-115, 800) content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "404": description: No application associated with the session. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "500": description: BFF or INPS internal error (Code 100) content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "503": description: Critical DB service unavailable (failure to read local state) content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" /receipt: get: tags: - Read-Only Operations summary: Retrieves the application receipt PDF (RichiediRicevuta) description: | Proxies INPS `RichiediRicevuta`. Returns the receipt PDF of the application, available only from state PROTOCOLLATA (40). The BFF verifies idLavorazione ownership before proxying. operationId: getApplicationReceipt responses: "200": description: Receipt PDF available. content: application/json: schema: $ref: "#/components/schemas/PdfDocumentResponse" "400": description: INPS validation / state error (Codes 100-115, 801) content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "404": description: No application associated with the session. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "500": description: BFF or INPS internal error (Code 100) content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "503": description: Critical DB service unavailable (failure to read local state) content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" components: securitySchemes: BearerAuth: type: http scheme: bearer bearerFormat: OpaqueToken description: Opaque token retrieved from the Authorization header for securing the BFF endpoints. parameters: IdempotencyKey: in: header name: Idempotency-Key required: true description: | Client-generated UUID identifying a single user action (intent). The same key MUST be reused when retrying the same action (e.g. after a network timeout) so the operation is replayed safely. A new key signals a new intent: replace the draft, overwrite the photo, etc. The BFF maps this client key to the per-step INPS Idempotency-Key it persists, guaranteeing the local record stays reconcilable with the INPS source of truth. schema: type: string format: uuid schemas: ApplicationState: type: string description: Internal workflow state (managed by the BFF/DB) that guides the FE's display logic. enum: - READY_FOR_NEW_DRAFT - DRAFT - READY_FOR_PHOTO_UPLOAD - UPLOADING_PHOTO - READY_FOR_DOCUMENTS_UPLOAD - UPLOADING_DOCUMENTS - ACQUIRED StateResponse: type: object properties: state: $ref: "#/components/schemas/ApplicationState" description: Current or final application state. ErrorDetail: type: object description: Detail of the error returned by INPS. properties: errorCode: type: string description: Original INPS error code (e.g., 700, 212, 903). description: type: string description: Human-readable error message. ErrorResponse: type: object description: Standardized structure for error handling. properties: error: type: object properties: type: type: string enum: - VALIDATION_ERROR - SYSTEM_ERROR - SERVICE_UNAVAILABLE description: Type of error managed by the BFF. details: $ref: "#/components/schemas/ErrorDetail" description: Specific details of the INPS or system error. # ---------------------------------------------------------------- # INPS Input Schemas (codiceFiscale excluded, handled by BFF from session) # ---------------------------------------------------------------- NuovaDomandaInBozzaRequest: type: object description: Request body for NuovaDomandaInBozza. The BFF injects the CodiceFiscale from the session. required: - informativaPrivacy - nome - cognome - sesso - statoNascita - dataNascita - idCittadinanza - siglaProvinciaRec - descrizioneComuneRec - capRec - indirizzoRec properties: informativaPrivacy: type: boolean description: 1=Acceptance of privacy policy nome: type: string maxLength: 50 description: Full name cognome: type: string maxLength: 50 description: Full surname sesso: type: string maxLength: 1 enum: [M, F] description: Gender statoNascita: type: string maxLength: 60 description: Full description of the State of Birth comuneNascita: type: string maxLength: 60 nullable: true description: Full description of the Municipality of Birth (Required if statoNascita is ITALIA) siglaProvinciaNascita: type: string maxLength: 2 nullable: true description: Province abbreviation of Birth (Required if statoNascita is ITALIA) dataNascita: type: string format: date-time description: Date of birth idCittadinanza: type: integer description: 0=Italiana, 2=Paesi comunitari, 3=Paesi extracomunitari dataScadenzaPermessoSoggiorno: type: string format: date-time nullable: true description: Permit expiration date (Required only if idCittadinanza = 3) pressoNome: type: string maxLength: 40 nullable: true description: Optional name for delivery pressoCognome: type: string maxLength: 40 nullable: true description: Optional surname for delivery. Pair PRESSO NOME/COGNOME is exclusive of PRESSO DENOMINAZIONE. pressoDenominazione: type: string maxLength: 40 nullable: true description: Optional Denomination for delivery. Length must not exceed 40 characters. siglaProvinciaRec: type: string maxLength: 2 description: Province abbreviation for delivery address descrizioneComuneRec: type: string maxLength: 60 description: Municipality description for delivery address capRec: type: string maxLength: 5 description: ZIP code for delivery address indirizzoRec: type: string maxLength: 30 description: Delivery address (max 30 characters) civicoRec: type: string maxLength: 10 nullable: true description: House number (max 10 characters) datiAggiuntiviRec: type: string maxLength: 45 nullable: true description: Additional address data (max 45 characters) FornisciFotoRequest: type: object description: Request body for FornisciFoto. The BFF injects the CodiceFiscale from the session. required: - idLavorazione - fotoCED - informativaFoto properties: idLavorazione: type: string maxLength: 20 description: The INPS idLavorazione of the draft application. fotoCED: type: string format: byte description: Photo encoded in Base64 (max 2Mb). informativaFoto: type: boolean description: 1=Acceptance of photo information. ConfermaDomandaRequest: type: object description: Request body for ConfermaDomanda (with optional documentation). The BFF injects the CodiceFiscale from the session. required: - idLavorazione properties: idLavorazione: type: string maxLength: 20 description: The INPS idLavorazione of the draft application. tipologiaUlterioreDocumentazione: type: string maxLength: 1 nullable: true description: 1 - Trento/Bolzano/Valle d’Aosta, 2 - Sentenza/Decreto, 3 - Invalidità ante 2010. enum: [1, 2, 3] nomeFile: type: string maxLength: 255 nullable: true description: Required if TipologiaUlterioreDocumentazione=1 or 3 allegato: type: string format: byte nullable: true description: Verbale in PDF encoded in Base64 (max 2Mb). Required if TipologiaUlterioreDocumentazione=1 or 3. siglaProvinciaTribunale: type: string maxLength: 2 nullable: true description: Required if TipologiaUlterioreDocumentazione=2 descrizioneComuneTribunale: type: string maxLength: 60 nullable: true description: Required if TipologiaUlterioreDocumentazione=2 dataSentenza: type: string format: date-time nullable: true description: Date of the Sentence/Homologation Decree. Required if TipologiaUlterioreDocumentazione=2. dichiarazioneConformitaVerbale: type: boolean nullable: true description: 1=YES. Required if TipologiaUlterioreDocumentazione=1 or 3. autodichiarazioneSentenza: type: boolean nullable: true description: 1=YES. Required if TipologiaUlterioreDocumentazione=2. dirittoAccompagnatore: type: boolean nullable: true description: 0=NO, 1=SI. Independent of documentation type. # ---------------------------------------------------------------- # Read-only response schemas (proxied from INPS) # ---------------------------------------------------------------- PdfDocumentResponse: type: object description: Wrapper for a Base64-encoded PDF document (summary or receipt) proxied from INPS. required: - document properties: document: type: string format: byte description: PDF document encoded in Base64 (max 1Mb). fileName: type: string description: Suggested file name for the document. StatusDetailResponse: type: object description: Detailed application/card status proxied from INPS RichiediStato. The card-related fields are only present when a card exists. properties: statoDomanda: type: integer nullable: true description: INPS application state (10, 30, 40, 50, 60, 70, 90, 99). Present only if the application exists. enum: [10, 30, 40, 50, 60, 70, 90, 99] note: type: string maxLength: 255 nullable: true description: Optional note on the application state (e.g. rejection reason). statoCarta: type: integer nullable: true description: INPS card state. Present only if the card exists. cartaAttiva: type: boolean nullable: true description: Whether the card is active. Present only if the card exists. annotazione: type: string maxLength: 255 nullable: true description: Note on the card state change. Present only if the card exists. DraftDataResponse: type: object description: Draft application data proxied from INPS RecuperoDatiDomanda, used to pre-fill the edit form. Includes the photo if already attached. required: - codiceFiscale - nome - cognome - sesso - statoNascita - dataNascita - idCittadinanza - siglaProvinciaRec - descrizioneComuneRec - capRec - indirizzoRec properties: codiceFiscale: type: string minLength: 16 maxLength: 16 nome: type: string maxLength: 50 cognome: type: string maxLength: 50 sesso: type: string enum: [M, F] statoNascita: type: string maxLength: 60 comuneNascita: type: string maxLength: 60 nullable: true description: Only for Italian citizenship. siglaProvinciaNascita: type: string maxLength: 2 nullable: true description: Only for Italian citizenship. dataNascita: type: string format: date-time idCittadinanza: type: integer enum: [0, 2, 3] description: 0=Italiana, 2=Paesi comunitari, 3=Paesi extracomunitari. dataScadenzaPermessoSoggiorno: type: string format: date-time nullable: true description: Only for extracomunitario citizens. pressoNome: type: string maxLength: 40 nullable: true pressoCognome: type: string maxLength: 40 nullable: true pressoDenominazione: type: string maxLength: 40 nullable: true siglaProvinciaRec: type: string maxLength: 2 descrizioneComuneRec: type: string maxLength: 60 capRec: type: string maxLength: 5 indirizzoRec: type: string maxLength: 30 civicoRec: type: string maxLength: 10 nullable: true datiAggiuntiviRec: type: string maxLength: 45 nullable: true fotoCED: type: string format: byte nullable: true description: Photo in Base64. Present only if already attached.