openapi: 3.0.3 info: title: CED Portal Backend version: 1.0.0 description: >- Backend API for the CED Operator Portal. Operator referents access the portal through Area Riservata to create the operator profile and manage the public data, access points, benefits, and opportunities offered to European Disability Card holders. servers: - url: https://api.ced.pagopa.it/api/ced-portal/v1 tags: - name: Auth - name: Profile - name: Places - name: Opportunities - name: Categories - name: Department paths: /operator/profile: get: tags: - Profile summary: Get the authenticated operator profile operationId: getOperatorProfile security: - bearerAuth: [] responses: "200": description: Operator profile content: application/json: schema: $ref: "#/components/schemas/OperatorProfileResponse" examples: onlinePlace: summary: Operator with online place value: displayName: Operatore Demo contactEmail: contatto@example.org operatorId: 01JVMK3N8XQZP5T6G2WYHAB4D0 place: id: 01JVMK3N8XQZP5T6G2WYHAB4CD type: online name: Sportello remoto website: url: https://example.org supportContacts: - id: 01JVMK3N8XQZP5T6G2WYHAB4CE type: email value: support@example.org - id: 01JVMK3N8XQZP5T6G2WYHAB4CF type: phone value: "+39 0000000000" offlinePlace: summary: Operator with offline place value: displayName: Operatore Demo contactEmail: contatto@example.org operatorId: 01JVMK3N8XQZP5T6G2WYHAB4D0 place: id: 01JVMK3N8XQZP5T6G2WYHAB4CG type: offline name: Sportello centrale address: street: Via Roma 1 city: Roma state: RM postalCode: "00100" country: IT supportContacts: - id: 01JVMK3N8XQZP5T6G2WYHAB4CH type: website value: https://example.org/support "401": description: Invalid or missing JWT content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" example: statusCode: 401 message: Unauthorized "403": description: Authenticated user is not an operator content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" example: statusCode: 403 message: Forbidden "404": description: No data associated with the authenticated operator content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" example: statusCode: 404 message: Operator profile not found post: tags: - Profile summary: Create the authenticated operator profile operationId: createOperatorProfile security: - bearerAuth: [] requestBody: required: true content: multipart/form-data: schema: type: object additionalProperties: false required: - profile - logo - image properties: profile: $ref: "#/components/schemas/OperatorProfileCreateRequest" logo: type: string format: binary description: >- PNG or JPEG logo, up to 300x300 pixels. The filename extension must match the image format. image: type: string format: binary description: >- PNG or JPEG profile image, up to 300x600 pixels. The filename extension must match the image format. encoding: profile: contentType: application/json responses: "201": description: Operator profile created successfully content: application/json: schema: $ref: "#/components/schemas/OperatorProfileResponse" "400": description: Invalid profile JSON or invalid image files content: application/problem+json: schema: $ref: "#/components/schemas/ErrorResponse" "401": description: Invalid or missing JWT content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" example: statusCode: 401 message: Unauthorized "403": description: Authenticated user is not an operator content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" example: statusCode: 403 message: Forbidden put: tags: - Profile summary: Replace the authenticated operator profile description: >- Replaces the profile fields represented by the required profile part. The authenticated operator must already have a profile. Omitted logo or image parts leave the corresponding asset unchanged. A supplied asset must have a filename extension matching its PNG or JPEG format. The profile place ID is preserved. Both privacyUrl and tosUrl are required HTTPS URLs on every replacement. operationId: updateOperatorProfile security: - bearerAuth: [] requestBody: required: true content: multipart/form-data: schema: type: object additionalProperties: false required: - profile properties: profile: $ref: "#/components/schemas/OperatorProfileCreateRequest" logo: type: string format: binary description: >- Optional PNG or JPEG logo, up to 300x300 pixels. Omit to keep the current logo. The filename extension must match the image format. image: type: string format: binary description: >- Optional PNG or JPEG profile image, up to 300x600 pixels. Omit to keep the current image. The filename extension must match the image format. encoding: profile: contentType: application/json responses: "200": description: Operator profile replaced successfully content: application/json: schema: $ref: "#/components/schemas/OperatorProfileResponse" "400": description: Invalid profile JSON or invalid image files content: application/problem+json: schema: $ref: "#/components/schemas/ErrorResponse" "401": description: Invalid or missing JWT content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" example: statusCode: 401 message: Unauthorized "403": description: Authenticated user is not an operator content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" example: statusCode: 403 message: Forbidden "404": description: No profile exists for the authenticated operator content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" example: statusCode: 404 message: Operator profile not found /operator/places: get: tags: - Places summary: List places for the authenticated operator operationId: listOperatorPlaces security: - bearerAuth: [] parameters: - name: offset in: query required: false schema: type: integer minimum: 0 default: 0 - name: limit in: query required: false schema: type: integer minimum: 1 maximum: 100 default: 20 - name: search in: query required: false description: Case-insensitive substring search on the place name. schema: type: string - name: type in: query required: false description: Filter by place type. When omitted, both types are included. schema: type: string enum: - online - offline responses: "200": description: Paginated list of operator places content: application/json: schema: $ref: "#/components/schemas/PlaceListResponse" examples: mixedPlaces: summary: Online and offline places value: items: - id: 01JVMK3N8XQZP5T6G2WYHAB4CD type: online name: Sportello remoto associatedOpportunities: 2 website: url: https://example.org supportContacts: - id: 01JVMK3N8XQZP5T6G2WYHAB4CE type: email value: support@example.org - id: 01JVMK3N8XQZP5T6G2WYHAB4CG type: offline name: Sportello centrale associatedOpportunities: 0 address: street: Via Roma 1 city: Roma state: RM postalCode: "00100" country: IT supportContacts: - id: 01JVMK3N8XQZP5T6G2WYHAB4CF type: phone value: "+39 0000000000" total: 2 "400": description: Invalid pagination or place type query parameter content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" "401": description: Invalid or missing JWT content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" example: statusCode: 401 message: Unauthorized "403": description: Authenticated user is not an operator content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" example: statusCode: 403 message: Forbidden post: tags: - Places summary: Create a place for the authenticated operator operationId: createOperatorPlace security: - bearerAuth: [] requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/PlaceCreateRequest" examples: onlinePlace: summary: Creating an online place value: type: online name: Sportello remoto website: url: https://example.org supportContacts: - type: email value: support@example.org offlinePlace: summary: Creating an offline place value: type: offline name: Sportello centrale address: street: Via Roma 1 city: Roma state: RM postalCode: "00100" country: IT supportContacts: - type: website value: https://example.org/support responses: "201": description: Place created successfully content: application/json: schema: $ref: "#/components/schemas/PlaceResponse" "400": description: Invalid place payload content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" example: statusCode: 400 message: Validation error "401": description: Invalid or missing JWT content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" example: statusCode: 401 message: Unauthorized "403": description: Authenticated user is not an operator content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" example: statusCode: 403 message: Forbidden /operator/places/{placeId}: get: tags: - Places summary: Get a place for the authenticated operator operationId: getOperatorPlace security: - bearerAuth: [] parameters: - name: placeId in: path required: true schema: type: string pattern: "^[0-9A-HJKMNP-TV-Z]{26}$" responses: "200": description: Operator place content: application/json: schema: $ref: "#/components/schemas/PlaceResponse" examples: onlinePlace: summary: Online place value: id: 01JVMK3N8XQZP5T6G2WYHAB4CD type: online name: Sportello remoto website: url: https://example.org supportContacts: - id: 01JVMK3N8XQZP5T6G2WYHAB4CE type: email value: support@example.org offlinePlace: summary: Offline place value: id: 01JVMK3N8XQZP5T6G2WYHAB4CG type: offline name: Sportello centrale address: street: Via Roma 1 city: Roma state: RM postalCode: "00100" country: IT supportContacts: - id: 01JVMK3N8XQZP5T6G2WYHAB4CH type: website value: https://example.org/support "401": description: Invalid or missing JWT content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" example: statusCode: 401 message: Unauthorized "403": description: Authenticated user is not an operator content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" example: statusCode: 403 message: Forbidden "404": description: Place not found content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" example: statusCode: 404 message: Place not found delete: tags: - Places summary: Delete a place of the authenticated operator description: >- Permanently deletes a place of the authenticated operator, together with its address or website, its support contacts and its links with opportunities. The place referenced by the operator profile is not exposed by this resource and answers 404: it is not returned by GET /operator/places nor by GET /operator/places/{placeId} either. operationId: deleteOperatorPlace security: - bearerAuth: [] parameters: - name: placeId in: path required: true schema: type: string pattern: "^[0-9A-HJKMNP-TV-Z]{26}$" responses: "204": description: Place deleted "400": description: "Invalid placeId: not a ULID" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" example: statusCode: 400 message: Validation error "401": description: Invalid or missing JWT content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" example: statusCode: 401 message: Unauthorized "403": description: Authenticated user is not an operator content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" example: statusCode: 403 message: Forbidden "404": description: Place not found content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" example: statusCode: 404 message: Place not found "412": description: >- The place is the only one of an opportunity that is published, suspended, or awaiting/passed testing and is not valid on the national territory content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" example: statusCode: 412 message: Place is the only one of an active opportunity and cannot be deleted /operator/opportunities/{opportunityId}: get: tags: - Opportunities summary: Get a single opportunity for the authenticated operator operationId: getOperatorOpportunity security: - bearerAuth: [] parameters: - name: opportunityId in: path required: true schema: type: string pattern: "^[0-9A-HJKMNP-TV-Z]{26}$" responses: "200": description: Opportunity detail content: application/json: schema: $ref: "#/components/schemas/OpportunityDetailResponse" "401": description: Invalid or missing JWT content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" example: statusCode: 401 message: Unauthorized "403": description: Authenticated user is not an operator content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" example: statusCode: 403 message: Forbidden "404": description: Opportunity not found content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" example: statusCode: 404 message: Opportunity not found put: tags: - Opportunities summary: Update an opportunity for the authenticated operator description: >- Replaces the writable representation of an opportunity. All required writable fields must be sent on every request; omitting an optional field (dateTo, url, or caregiverBenefit) clears its current value. A real change to the benefit economics on a scheduled/published/suspended opportunity moves it back to review (test_pending); every other change applies immediately. The current updatedAt must be echoed back for optimistic-concurrency control. operationId: operatorUpdateOpportunity security: - bearerAuth: [] parameters: - name: opportunityId in: path required: true schema: type: string pattern: "^[0-9A-HJKMNP-TV-Z]{26}$" requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/OpportunityUpdateRequest" example: updatedAt: "2026-01-01T00:00:00.000Z" url: https://example.org/updated-promo responses: "204": description: Opportunity updated (applied immediately or moved to review) "400": description: Invalid update payload content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" example: statusCode: 400 message: Validation error "401": description: Invalid or missing JWT content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" example: statusCode: 401 message: Unauthorized "403": description: Authenticated user is not an operator content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" example: statusCode: 403 message: Forbidden "404": description: Opportunity not found content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" example: statusCode: 404 message: Opportunity not found "409": description: Opportunity was modified concurrently (stale updatedAt) content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" example: statusCode: 409 message: Opportunity was modified concurrently "412": description: >- Precondition failed: the opportunity cannot be modified in its current state (under review, or a scheduled suspension is pending). content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" example: statusCode: 412 message: "Precondition failed: Opportunity is under review and cannot be modified" /operator/opportunities/{opportunityId}/request-test: patch: tags: - Opportunities summary: Request testing for a draft or test_rejected opportunity operationId: operatorRequestOpportunityTest security: - bearerAuth: [] parameters: - name: opportunityId in: path required: true schema: type: string pattern: "^[0-9A-HJKMNP-TV-Z]{26}$" responses: "204": description: Testing requested successfully "401": description: Invalid or missing JWT content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" example: statusCode: 401 message: Unauthorized "403": description: Authenticated user is not an operator content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" example: statusCode: 403 message: Forbidden "404": description: Opportunity not found content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" example: statusCode: 404 message: Opportunity not found "409": description: Opportunity status was modified concurrently content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" example: statusCode: 409 message: Opportunity status was modified concurrently "412": description: >- Opportunity is not in draft or test_rejected status, or has neither places nor national territory coverage content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" example: statusCode: 412 message: Opportunity is not in draft or test_rejected status /operator/opportunities/{opportunityId}/publish: patch: summary: Publish an approved opportunity operationId: operatorPublishOpportunity tags: - Opportunities security: - bearerAuth: [] parameters: - name: opportunityId in: path required: true schema: type: string pattern: "^[0-9A-HJKMNP-TV-Z]{26}$" responses: "204": description: Opportunity published successfully. "401": description: Invalid or missing JWT content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" example: statusCode: 401 message: Unauthorized "403": description: Authenticated user is not an operator content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" example: statusCode: 403 message: Forbidden "404": description: Opportunity not found content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" example: statusCode: 404 message: Opportunity not found "409": description: Opportunity status was modified concurrently content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" example: statusCode: 409 message: Opportunity status was modified concurrently "412": description: >- Precondition failed: the opportunity is not in test_passed status, or the operator has no profile. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" examples: notTestPassed: summary: Opportunity is not in test_passed status value: statusCode: 412 message: "Precondition failed: Opportunity must be in test_passed status to be published" operatorHasNoProfile: summary: Operator has no profile value: statusCode: 412 message: "Precondition failed: Operator must have a profile to publish an opportunity" /operator/opportunities/{opportunityId}/delete: patch: tags: - Opportunities summary: Delete an operator's own opportunity (soft delete) operationId: operatorDeleteOpportunity security: - bearerAuth: [] parameters: - name: opportunityId in: path required: true schema: type: string pattern: "^[0-9A-HJKMNP-TV-Z]{26}$" requestBody: required: false content: application/json: schema: type: object additionalProperties: false properties: deletionMessage: type: string minLength: 1 maxLength: 4096 description: >- Reason for deletion. Required for every deletable status except "draft" (i.e. required for test_rejected, scheduled and suspended). Leading/trailing whitespace is trimmed; must be non-empty once trimmed. responses: "204": description: Opportunity deleted successfully "400": description: >- Invalid payload, or deletion reason missing for a non-draft opportunity content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" example: statusCode: 400 message: "Validation error: A deletion reason is required to delete this opportunity" "401": description: Invalid or missing JWT content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" example: statusCode: 401 message: Unauthorized "403": description: Authenticated user is not an operator content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" example: statusCode: 403 message: Forbidden "404": description: Opportunity not found content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" example: statusCode: 404 message: Opportunity not found "409": description: Opportunity status was modified concurrently content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" example: statusCode: 409 message: Opportunity status was modified concurrently "412": description: >- The opportunity is in a status that cannot be deleted (an already-effective published opportunity must be suspended first, or it is under review) content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" examples: mustBeSuspended: summary: Already-effective published opportunity value: statusCode: 412 message: "Precondition failed: Opportunity must be suspended before deletion" underReview: summary: Opportunity under review value: statusCode: 412 message: "Precondition failed: Opportunity cannot be deleted while under review" /operator/opportunities/{opportunityId}/suspension/schedule: patch: tags: - Opportunities summary: Suspend an operator's own opportunity (immediate or scheduled) operationId: operatorSuspendOpportunity security: - bearerAuth: [] parameters: - name: opportunityId in: path required: true schema: type: string pattern: "^[0-9A-HJKMNP-TV-Z]{26}$" requestBody: required: true content: application/json: schema: type: object additionalProperties: false required: - suspensionMessage - suspendFrom properties: suspensionMessage: type: string minLength: 1 maxLength: 4096 description: >- Reason for suspension. Leading/trailing whitespace is trimmed; must be non-empty once trimmed. suspendFrom: type: string format: date description: >- Calendar date (ISO 8601) from which the suspension takes effect. If it is today or in the past, the suspension is applied immediately; if it is a future day, the suspension is scheduled for that day. responses: "204": description: Opportunity suspended or suspension scheduled successfully "400": description: >- Invalid payload: suspensionMessage missing/empty, or suspendFrom missing or not a valid ISO 8601 date. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" examples: missingSuspensionMessage: summary: Suspension message is missing or empty value: statusCode: 400 message: "Validation error: suspensionMessage is required" missingSuspendFrom: summary: suspendFrom is missing or not a valid date value: statusCode: 400 message: "Validation error: suspendFrom is required" "401": description: Invalid or missing JWT content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" example: statusCode: 401 message: Unauthorized "403": description: Authenticated user is not an operator content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" example: statusCode: 403 message: Forbidden "404": description: Opportunity not found content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" example: statusCode: 404 message: Opportunity not found "409": description: Opportunity status was modified concurrently content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" example: statusCode: 409 message: Opportunity status was modified concurrently "412": description: >- Precondition failed: the opportunity cannot be suspended in its current state. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" examples: notPublished: summary: Opportunity is not in published status value: statusCode: 412 message: "Precondition failed: Opportunity must be in published status to be suspended" notYetLive: summary: Opportunity is published but not yet live (dateFrom in the future) value: statusCode: 412 message: "Precondition failed: Opportunity is not yet live and cannot be suspended" suspensionAlreadyPending: summary: A scheduled suspension is already pending value: statusCode: 412 message: "Precondition failed: A scheduled suspension is already pending for this opportunity" /operator/opportunities/{opportunityId}/suspension/cancel: patch: tags: - Opportunities summary: Cancel a pending scheduled suspension for an operator's own opportunity description: >- Only suspensions scheduled by the operator can be cancelled: a department-scheduled suspension is out of the operator's reach. operationId: operatorCancelScheduledSuspension security: - bearerAuth: [] parameters: - name: opportunityId in: path required: true schema: type: string pattern: "^[0-9A-HJKMNP-TV-Z]{26}$" responses: "204": description: Scheduled suspension cancelled successfully "401": description: Invalid or missing JWT content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" example: statusCode: 401 message: Unauthorized "403": description: Authenticated user is not an operator content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" example: statusCode: 403 message: Forbidden "404": description: Opportunity not found content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" example: statusCode: 404 message: Opportunity not found "409": description: >- The scheduled suspension was already applied by the background job before this request was processed content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" example: statusCode: 409 message: Opportunity status was modified concurrently "412": description: >- No scheduled suspension is pending for this opportunity, or the pending suspension was scheduled by the department. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" examples: noPendingSuspension: summary: No scheduled suspension is pending value: statusCode: 412 message: "Precondition failed: No scheduled suspension is pending for this opportunity" departmentScheduled: summary: The pending suspension was scheduled by the department value: statusCode: 412 message: "Precondition failed: Only the department can cancel a department-scheduled suspension" /operator/opportunities/{opportunityId}/republish: patch: tags: - Opportunities summary: Republish the operator's own suspended opportunity description: >- Lifts a suspension the operator applied itself and makes the opportunity visible on IO again. The suspension reason and actor are cleared. A department-applied suspension is out of the operator's reach. operationId: operatorRepublishOpportunity security: - bearerAuth: [] parameters: - name: opportunityId in: path required: true schema: type: string pattern: "^[0-9A-HJKMNP-TV-Z]{26}$" responses: "204": description: Opportunity republished "400": description: "Invalid opportunityId: not a ULID" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" example: statusCode: 400 message: Validation error "401": description: Invalid or missing JWT content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" example: statusCode: 401 message: Unauthorized "403": description: Authenticated user is not an operator content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" example: statusCode: 403 message: Forbidden "404": description: Opportunity not found content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" example: statusCode: 404 message: Opportunity not found "409": description: Opportunity status was modified concurrently content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" example: statusCode: 409 message: Conflict "412": description: >- The opportunity is not suspended, or it was suspended by the department, or its end date is not in the future. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" example: statusCode: 412 message: Opportunity must be suspended to be republished /operator/opportunities/{opportunityId}/republish/request: patch: tags: - Opportunities summary: Request republication of a department-suspended opportunity description: >- Asks the department to republish an opportunity it suspended. A reason is required. The opportunity stays suspended: only the department can approve the request, through the republish endpoint, or reject it. A pending request from a previous cycle must be decided first. operationId: operatorRequestOpportunityRepublish security: - bearerAuth: [] parameters: - name: opportunityId in: path required: true schema: type: string pattern: "^[0-9A-HJKMNP-TV-Z]{26}$" requestBody: required: true content: application/json: schema: type: object additionalProperties: false required: - republishMessage properties: republishMessage: type: string minLength: 1 maxLength: 4096 description: >- Reason the operator asks for the opportunity to be republished. Leading/trailing whitespace is trimmed; must be non-empty once trimmed. responses: "204": description: Request registered, the opportunity stays suspended "400": description: "Invalid payload: republishMessage missing, empty or too long" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" example: statusCode: 400 message: "Validation error: republishMessage is required" "401": description: Invalid or missing JWT content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" example: statusCode: 401 message: Unauthorized "403": description: Forbidden — admin userType not allowed content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" example: statusCode: 403 message: Forbidden "404": description: Opportunity not found or not owned by the operator content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" example: statusCode: 404 message: Opportunity not found "409": description: Concurrent status modification content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" example: statusCode: 409 message: Conflict "412": description: >- The opportunity is not suspended, or it was suspended by the operator itself, or a republish request is already pending. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" example: statusCode: 412 message: Precondition Failed /operator/opportunities: get: tags: - Opportunities summary: List opportunities for the authenticated operator operationId: listOperatorOpportunities security: - bearerAuth: [] parameters: - name: offset in: query required: false schema: type: integer minimum: 0 default: 0 - name: limit in: query required: false schema: type: integer minimum: 1 maximum: 100 default: 20 - name: status in: query required: false description: >- Filter by opportunity status. "scheduled" and "scheduled_suspension" are derived statuses (not stored): "scheduled" matches published opportunities whose dateFrom is still in the future; "published" matches those already effective (dateFrom <= today) with no future suspendFrom; "scheduled_suspension" matches live published opportunities with a future suspendFrom. schema: type: string enum: - draft - test_pending - test_rejected - test_passed - published - scheduled - scheduled_suspension - suspended - name: search in: query required: false description: Case-insensitive text search on the opportunity name. schema: type: string - name: categoryId in: query required: false schema: type: string pattern: "^[0-9A-HJKMNP-TV-Z]{26}$" - name: sortBy in: query required: false schema: type: string enum: - createdAt - updatedAt default: createdAt - name: sortOrder in: query required: false schema: type: string enum: - asc - desc default: desc responses: "200": description: Paginated list of operator opportunities content: application/json: schema: $ref: "#/components/schemas/OpportunityListResponse" "401": description: Invalid or missing JWT content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" example: statusCode: 401 message: Unauthorized "403": description: Authenticated user is not an operator content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" example: statusCode: 403 message: Forbidden post: tags: - Opportunities summary: Create an opportunity for the authenticated operator operationId: createOperatorOpportunity security: - bearerAuth: [] requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/OpportunityCreateRequest" examples: discountBenefit: summary: Opportunity with discount benefit value: dateFrom: "2026-01-01" dateTo: "2026-12-31" url: https://example.org/promo categoryId: 01KRJXEYD44B58700GT982CCYY placeIds: - 01JVMK3N8XQZP5T6G2WYHAB4CD beneficiaryBenefit: type: discount discountType: percentage value: 20 caregiverBenefit: type: free localizedMetadata: - key: name language: it value: Sconto 20% - key: description language: it value: Sconto del 20% su tutti i servizi responses: "201": description: Opportunity created successfully content: application/json: schema: $ref: "#/components/schemas/OpportunityDetailResponse" "400": description: Invalid opportunity payload content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" example: statusCode: 400 message: Validation error "401": description: Invalid or missing JWT content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" example: statusCode: 401 message: Unauthorized "403": description: Authenticated user is not an operator content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" example: statusCode: 403 message: Forbidden /opportunities: get: tags: - Opportunities summary: List all opportunities across all operators (department only) operationId: adminListOpportunities security: - bearerAuth: [] parameters: - name: offset in: query required: false schema: type: integer minimum: 0 default: 0 - name: limit in: query required: false schema: type: integer minimum: 1 maximum: 100 default: 20 - name: status in: query required: false description: >- Filter by opportunity status. "scheduled" and "scheduled_suspension" are derived statuses (not stored): "scheduled" matches published opportunities whose dateFrom is still in the future; "published" matches those already effective (dateFrom <= today) with no future suspendFrom; "scheduled_suspension" matches live published opportunities with a future suspendFrom. schema: type: string enum: - draft - test_pending - test_rejected - test_passed - published - scheduled - scheduled_suspension - suspended - deleted - name: search in: query required: false description: >- Case-insensitive text search on the opportunity name and the operator name. schema: type: string - name: sortBy in: query required: false schema: type: string enum: - createdAt - updatedAt default: createdAt - name: sortOrder in: query required: false schema: type: string enum: - asc - desc default: desc - name: operatorId in: query required: false schema: type: string pattern: "^[0-9A-HJKMNP-TV-Z]{26}$" - name: categoryId in: query required: false schema: type: string pattern: "^[0-9A-HJKMNP-TV-Z]{26}$" - name: dateFrom in: query required: false schema: type: string format: date - name: dateTo in: query required: false schema: type: string format: date responses: "200": description: Paginated list of opportunities across all operators content: application/json: schema: $ref: "#/components/schemas/AdminOpportunityListResponse" "401": description: Invalid or missing JWT content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" example: statusCode: 401 message: Unauthorized "403": description: Forbidden — operator userType not allowed content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" example: statusCode: 403 message: Forbidden /opportunities/{opportunityId}: get: tags: - Opportunities summary: Get a single opportunity (department only) operationId: getOpportunity security: - bearerAuth: [] parameters: - name: opportunityId in: path required: true schema: type: string pattern: "^[0-9A-HJKMNP-TV-Z]{26}$" responses: "200": description: Opportunity detail content: application/json: schema: $ref: "#/components/schemas/OpportunityDetailAdminResponse" "401": description: Invalid or missing JWT content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" example: statusCode: 401 message: Unauthorized "403": description: Forbidden — operator userType not allowed content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" example: statusCode: 403 message: Forbidden "404": description: Opportunity not found content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" example: statusCode: 404 message: Opportunity not found /opportunities/{opportunityId}/approve: patch: tags: - Opportunities summary: Approve an opportunity for publication (department only) operationId: approveOpportunity security: - bearerAuth: [] parameters: - name: opportunityId in: path required: true schema: type: string pattern: "^[0-9A-HJKMNP-TV-Z]{26}$" requestBody: required: false content: application/json: schema: type: object additionalProperties: false properties: dateFrom: type: string format: date responses: "204": description: Opportunity approved "401": description: Invalid or missing JWT content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" example: statusCode: 401 message: Unauthorized "403": description: Forbidden — operator userType not allowed content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" example: statusCode: 403 message: Forbidden "404": description: Opportunity not found content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" example: statusCode: 404 message: Opportunity not found "409": description: Concurrent status modification content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" example: statusCode: 409 message: Conflict "412": description: Opportunity not in test_pending or test_rejected status content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" example: statusCode: 412 message: Precondition Failed /opportunities/{opportunityId}/request-changes: patch: tags: - Opportunities summary: Request changes on an opportunity under review (department only) description: >- Sends the operator a change request on an opportunity under review. The opportunity moves to "test_rejected" and becomes editable by the operator again, which can then send it back for review. The message overwrites any change request from a previous review cycle. operationId: requestOpportunityChanges security: - bearerAuth: [] parameters: - name: opportunityId in: path required: true schema: type: string pattern: "^[0-9A-HJKMNP-TV-Z]{26}$" requestBody: required: true content: application/json: schema: type: object additionalProperties: false required: - changeRequestMessage properties: changeRequestMessage: type: string minLength: 1 maxLength: 4096 description: >- Changes the operator is asked to make (raw text). Leading/trailing whitespace is trimmed; must be non-empty once trimmed. responses: "204": description: Changes requested, opportunity back to draft "400": description: "Invalid payload: changeRequestMessage missing, empty or too long" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" example: statusCode: 400 message: "Validation error: changeRequestMessage is required" "401": description: Invalid or missing JWT content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" example: statusCode: 401 message: Unauthorized "403": description: Forbidden — operator userType not allowed content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" example: statusCode: 403 message: Forbidden "404": description: Opportunity not found content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" example: statusCode: 404 message: Opportunity not found "409": description: Concurrent status modification content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" example: statusCode: 409 message: Conflict "412": description: Opportunity not in test_pending status content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" example: statusCode: 412 message: Precondition Failed /opportunities/{opportunityId}/suspension/schedule: patch: tags: - Opportunities summary: Suspend a partner opportunity (department only, immediate or scheduled) description: >- Suspends a published partner opportunity, immediately or from a future date. A pending scheduled suspension does not block the department: an immediate suspension absorbs it, a new scheduled date overwrites it (date, message and actor). operationId: suspendOpportunity security: - bearerAuth: [] parameters: - name: opportunityId in: path required: true schema: type: string pattern: "^[0-9A-HJKMNP-TV-Z]{26}$" requestBody: required: true content: application/json: schema: type: object additionalProperties: false required: - suspensionMessage - suspendFrom properties: suspensionMessage: type: string minLength: 1 maxLength: 4096 description: >- Reason for suspension. Leading/trailing whitespace is trimmed; must be non-empty once trimmed. suspendFrom: type: string format: date description: >- Calendar date (ISO 8601) from which the suspension takes effect. If it is today or in the past, the suspension is applied immediately; if it is a future day, the suspension is scheduled for that day. responses: "204": description: Opportunity suspended or suspension scheduled successfully "400": description: >- Invalid payload: suspensionMessage missing/empty, or suspendFrom missing or not a valid ISO 8601 date. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" examples: missingSuspensionMessage: summary: Suspension message is missing or empty value: statusCode: 400 message: "Validation error: suspensionMessage is required" missingSuspendFrom: summary: suspendFrom is missing or not a valid date value: statusCode: 400 message: "Validation error: suspendFrom is required" "401": description: Invalid or missing JWT content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" example: statusCode: 401 message: Unauthorized "403": description: Forbidden — operator userType not allowed content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" example: statusCode: 403 message: Forbidden "404": description: Opportunity not found content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" example: statusCode: 404 message: Opportunity not found "409": description: Opportunity status was modified concurrently content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" example: statusCode: 409 message: Opportunity status was modified concurrently "412": description: >- Precondition failed: the opportunity cannot be suspended in its current state. A pending scheduled suspension is NOT a precondition failure for the department (override). content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" examples: notPublished: summary: Opportunity is not in published status value: statusCode: 412 message: "Precondition failed: Opportunity must be in published status to be suspended" notYetLive: summary: Opportunity is published but not yet live (dateFrom in the future) value: statusCode: 412 message: "Precondition failed: Opportunity is not yet live and cannot be suspended" /opportunities/{opportunityId}/suspension/cancel: patch: tags: - Opportunities summary: Cancel a pending scheduled suspension (department only, absolute) description: >- Cancels any pending scheduled suspension, whether it was scheduled by the department or by the operator. operationId: cancelScheduledSuspension security: - bearerAuth: [] parameters: - name: opportunityId in: path required: true schema: type: string pattern: "^[0-9A-HJKMNP-TV-Z]{26}$" responses: "204": description: Scheduled suspension cancelled successfully "401": description: Invalid or missing JWT content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" example: statusCode: 401 message: Unauthorized "403": description: Forbidden — operator userType not allowed content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" example: statusCode: 403 message: Forbidden "404": description: Opportunity not found content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" example: statusCode: 404 message: Opportunity not found "409": description: >- The scheduled suspension was already applied by the background job before this request was processed content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" example: statusCode: 409 message: Opportunity status was modified concurrently "412": description: No scheduled suspension is pending for this opportunity content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" example: statusCode: 412 message: "Precondition failed: No scheduled suspension is pending for this opportunity" /opportunities/{opportunityId}/republish: patch: tags: - Opportunities summary: Republish a suspended opportunity (department only, absolute) description: >- Lifts an active suspension and makes the opportunity visible on IO again, whether it was suspended by the department or by the operator. The suspension reason and actor are cleared. A pending scheduled suspension is not affected: use the suspension/cancel endpoint for that. operationId: republishOpportunity security: - bearerAuth: [] parameters: - name: opportunityId in: path required: true schema: type: string pattern: "^[0-9A-HJKMNP-TV-Z]{26}$" responses: "204": description: Opportunity republished "400": description: "Invalid opportunityId: not a ULID" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" example: statusCode: 400 message: Validation error "401": description: Invalid or missing JWT content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" example: statusCode: 401 message: Unauthorized "403": description: Authenticated user is not a department admin content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" example: statusCode: 403 message: Forbidden "404": description: Opportunity not found content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" example: statusCode: 404 message: Opportunity not found "409": description: Opportunity status was modified concurrently content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" example: statusCode: 409 message: Conflict "412": description: >- The opportunity is not suspended. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" example: statusCode: 412 message: Opportunity must be suspended to be republished /opportunities/{opportunityId}/republish/reject: patch: tags: - Opportunities summary: Reject a pending republish request (department only) description: >- Rejects the operator's request to republish a suspended opportunity. The opportunity stays suspended, the request is cleared and the reason given here replaces it. operationId: rejectOpportunityRepublish security: - bearerAuth: [] parameters: - name: opportunityId in: path required: true schema: type: string pattern: "^[0-9A-HJKMNP-TV-Z]{26}$" requestBody: required: true content: application/json: schema: type: object additionalProperties: false required: - republishRejectionMessage properties: republishRejectionMessage: type: string minLength: 1 maxLength: 4096 description: >- Reason the request is rejected. Leading/trailing whitespace is trimmed; must be non-empty once trimmed. responses: "204": description: Request rejected, the opportunity stays suspended "400": description: "Invalid payload: republishRejectionMessage missing, empty or too long" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" example: statusCode: 400 message: "Validation error: republishRejectionMessage is required" "401": description: Invalid or missing JWT content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" example: statusCode: 401 message: Unauthorized "403": description: Forbidden — operator userType not allowed content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" example: statusCode: 403 message: Forbidden "404": description: Opportunity not found content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" example: statusCode: 404 message: Opportunity not found "409": description: Concurrent status modification content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" example: statusCode: 409 message: Conflict "412": description: No republish request is pending on this opportunity content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" example: statusCode: 412 message: Precondition Failed /opportunity-categories: get: tags: - Categories summary: List all opportunity categories operationId: listOpportunityCategories security: - bearerAuth: [] responses: "200": description: List of opportunity categories content: application/json: schema: type: array items: $ref: "#/components/schemas/OpportunityCategoryItem" "401": description: Invalid or missing JWT content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" example: statusCode: 401 message: Unauthorized "403": description: Authenticated user is not an operator content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" example: statusCode: 403 message: Forbidden /acs: get: tags: - Auth summary: Assertion Consumer Service callback description: >- Receives an authentication token from the identity provider in the Authorization header, validates it, and creates a session. operationId: acs security: - bearerAuth: [] responses: "200": description: One-time session ID content: application/json: schema: type: object required: - sessionId properties: sessionId: type: string "400": description: Invalid or missing token content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" example: statusCode: 400 message: Validation error /authorize: get: tags: - Auth summary: Exchange a one-time session ID for session details description: >- Consumes the one-time session ID produced by the ACS endpoint and returns the session token together with operator details. operationId: authorize security: [] parameters: - name: id in: query required: true schema: type: string minLength: 1 responses: "200": description: Session details content: application/json: schema: $ref: "#/components/schemas/AuthorizeResponse" "404": description: Session not found content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" example: statusCode: 404 message: Session not found /department/onboardings: get: tags: - Department summary: List onboarding requests description: >- Returns a paginated list of onboarding requests for the configured product. Non-PENDING_IN_REVIEW items are enriched with an opportunity count from the local database. operationId: listOnboardings security: - bearerAuth: [] parameters: - name: page in: query required: false schema: type: integer minimum: 0 default: 0 - name: size in: query required: false schema: type: integer minimum: 1 maximum: 100 default: 20 - name: statuses in: query required: false schema: type: array items: type: string enum: - REQUEST - TOBEVALIDATED - PENDING - PENDING_IN_REVIEW - COMPLETED - FAILED - REJECTED - DELETED - name: name in: query required: false description: Filter onboardings by institution name. schema: type: string responses: "200": description: Paginated list of pending onboarding requests content: application/json: schema: $ref: "#/components/schemas/PendingOnboardingsResponse" "401": description: Unauthorized content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" example: statusCode: 401 message: Unauthorized "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" example: statusCode: 403 message: Forbidden /department/onboardings/{onboardingId}: get: tags: - Department summary: Get an onboarding by ID description: >- Retrieves a single onboarding request by its ID from Area Riservata. Returns 404 if the onboarding is not found. operationId: getOnboarding security: - bearerAuth: [] parameters: - name: onboardingId in: path required: true schema: type: string responses: "200": description: Onboarding found content: application/json: schema: $ref: "#/components/schemas/OnboardingDetail" "401": description: Unauthorized content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" example: statusCode: 401 message: Unauthorized "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" example: statusCode: 403 message: Forbidden "404": description: Not Found content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" example: statusCode: 404 message: Not Found /department/onboardings/{onboardingId}/complete: put: tags: - Department summary: Complete an onboarding request description: >- Uploads the signed contract for the given onboarding and triggers the completion workflow on Area Riservata. operationId: completeOnboarding security: - bearerAuth: [] parameters: - name: onboardingId in: path required: true schema: type: string requestBody: required: true content: multipart/form-data: schema: type: object required: - contract properties: contract: type: string format: binary responses: "200": description: Onboarding completed successfully "401": description: Unauthorized content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" example: statusCode: 401 message: Unauthorized "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" example: statusCode: 403 message: Forbidden /department/onboardings/{onboardingId}/contract: get: tags: - Department summary: Download the signed contract for an onboarding description: >- Downloads the signed contract file associated with the specified onboarding from Area Riservata. operationId: getContractSigned security: - bearerAuth: [] parameters: - name: onboardingId in: path required: true schema: type: string responses: "200": description: Signed contract file content: application/octet-stream: schema: type: string format: binary "401": description: Unauthorized content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" example: statusCode: 401 message: Unauthorized "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" example: statusCode: 403 message: Forbidden /department/onboardings/{onboardingId}/reject: patch: tags: - Department summary: Reject an onboarding request (department only) description: >- Rejects a pending onboarding request, recording the reason on Area Riservata, which notifies the institution. Nothing is persisted on this side: a rejected request never becomes an operator. The action applies only to requests still under review and is irreversible. operationId: adminRejectOnboarding security: - bearerAuth: [] parameters: - name: onboardingId in: path required: true schema: type: string requestBody: required: true content: application/json: schema: type: object additionalProperties: false required: - rejectionMessage properties: rejectionMessage: type: string minLength: 1 maxLength: 4096 description: >- Reason for the rejection. Recorded on Area Riservata and sent to the institution. responses: "204": description: Onboarding request rejected "400": description: "Invalid payload: rejectionMessage missing, empty or too long" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" example: statusCode: 400 message: "Validation error: rejectionMessage is required" "401": description: Unauthorized content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" example: statusCode: 401 message: Unauthorized "403": description: Forbidden content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" example: statusCode: 403 message: Forbidden "404": description: Onboarding not found content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" example: statusCode: 404 message: Onboarding not found "412": description: >- The onboarding request is not under review. A completed onboarding is revoked, not rejected. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" example: statusCode: 412 message: Precondition Failed /department/onboardings/{onboardingId}/revoke: patch: tags: - Department summary: Revoke the contract with an operator (department only) description: >- Terminates the agreement with the operator behind the given onboarding. The revocation is propagated to Area Riservata first, then every active session of the operator is revoked and all its published opportunities are suspended. The operator record may not exist yet — it is created at the referent's first login — in which case only the propagation and the session revocation take effect. The action is irreversible. operationId: adminRevokeOperator security: - bearerAuth: [] parameters: - name: onboardingId in: path required: true schema: type: string requestBody: required: false content: application/json: schema: type: object additionalProperties: false properties: revocationMessage: type: string minLength: 1 maxLength: 4096 description: >- Reason for the revocation, recorded on the operator and kept in the audit trail. Optional: when omitted the column is set to null and the audit records the revocation without a reason. Leading/trailing whitespace is trimmed; must be non-empty once trimmed. responses: "204": description: Operator revoked "400": description: "Invalid payload: revocationMessage present but empty or too long" content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" example: statusCode: 400 message: "Validation error: revocationMessage must not be empty" "401": description: Invalid or missing JWT content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" example: statusCode: 401 message: Unauthorized "403": description: Forbidden — operator userType not allowed content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" example: statusCode: 403 message: Forbidden "404": description: Onboarding not found content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" example: statusCode: 404 message: Onboarding not found "409": description: The operator has already been revoked content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" example: statusCode: 409 message: Conflict "412": description: >- Onboarding not in COMPLETED status. A request that is not yet completed is rejected, not revoked. content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" example: statusCode: 412 message: Precondition Failed components: securitySchemes: bearerAuth: type: http scheme: bearer bearerFormat: JWT schemas: OperatorProfileCreateRequest: type: object additionalProperties: false required: - contactEmail - displayName - place - privacyUrl - tosUrl properties: contactEmail: type: string format: email maxLength: 512 displayName: type: string maxLength: 512 place: $ref: "#/components/schemas/PlaceCreateRequest" privacyUrl: type: string format: uri pattern: "^[Hh][Tt][Tt][Pp][Ss]:[/][/]" maxLength: 2048 description: HTTPS link to the operator's privacy notice. tosUrl: type: string format: uri pattern: "^[Hh][Tt][Tt][Pp][Ss]:[/][/]" maxLength: 2048 description: HTTPS link to the operator's terms and conditions of use. PlaceBase: type: object additionalProperties: false required: - type - name - supportContacts properties: type: type: string enum: - online - offline name: type: string maxLength: 512 supportContacts: type: array items: $ref: "#/components/schemas/SupportContactCreateRequest" PlaceCreateRequest: oneOf: - $ref: "#/components/schemas/OnlinePlaceCreateRequest" - $ref: "#/components/schemas/OfflinePlaceCreateRequest" discriminator: propertyName: type mapping: online: "#/components/schemas/OnlinePlaceCreateRequest" offline: "#/components/schemas/OfflinePlaceCreateRequest" OfflinePlaceCreateRequest: allOf: - $ref: "#/components/schemas/PlaceBase" - type: object additionalProperties: false required: - address properties: address: $ref: "#/components/schemas/Address" OnlinePlaceCreateRequest: allOf: - $ref: "#/components/schemas/PlaceBase" - type: object additionalProperties: false required: - website properties: website: $ref: "#/components/schemas/Website" PlaceResponseBase: type: object additionalProperties: false required: - id - type - name - supportContacts properties: id: type: string pattern: "^[0-9A-HJKMNP-TV-Z]{26}$" type: type: string enum: - online - offline name: type: string maxLength: 512 supportContacts: type: array items: $ref: "#/components/schemas/SupportContactResponse" OfflinePlaceResponse: allOf: - $ref: "#/components/schemas/PlaceResponseBase" - type: object additionalProperties: false required: - address properties: address: $ref: "#/components/schemas/Address" OnlinePlaceResponse: allOf: - $ref: "#/components/schemas/PlaceResponseBase" - type: object additionalProperties: false required: - website properties: website: $ref: "#/components/schemas/Website" PlaceResponse: oneOf: - $ref: "#/components/schemas/OnlinePlaceResponse" - $ref: "#/components/schemas/OfflinePlaceResponse" discriminator: propertyName: type mapping: online: "#/components/schemas/OnlinePlaceResponse" offline: "#/components/schemas/OfflinePlaceResponse" PlaceListItem: type: object additionalProperties: false required: - id - type - name - supportContacts - associatedOpportunities properties: id: $ref: "#/components/schemas/PlaceResponseBase/properties/id" type: $ref: "#/components/schemas/PlaceResponseBase/properties/type" name: $ref: "#/components/schemas/PlaceResponseBase/properties/name" supportContacts: $ref: "#/components/schemas/PlaceResponseBase/properties/supportContacts" address: $ref: "#/components/schemas/Address" website: $ref: "#/components/schemas/Website" associatedOpportunities: type: integer minimum: 0 description: >- Number of currently linked opportunities belonging to the operator, excluding deleted opportunities and including all other statuses. oneOf: - type: object required: - website properties: type: type: string enum: - online website: $ref: "#/components/schemas/Website" - type: object required: - address properties: type: type: string enum: - offline address: $ref: "#/components/schemas/Address" PlaceListResponse: type: object additionalProperties: false required: - items - total properties: items: type: array items: $ref: "#/components/schemas/PlaceListItem" total: type: integer minimum: 0 description: Number of matching places before pagination. OperatorProfileResponse: type: object additionalProperties: false required: - contactEmail - displayName - operatorId - place - privacyUrl - tosUrl properties: contactEmail: type: string format: email maxLength: 512 displayName: type: string maxLength: 512 operatorId: type: string pattern: "^[0-9A-HJKMNP-TV-Z]{26}$" description: Unique identifier of the operator. place: $ref: "#/components/schemas/PlaceResponse" privacyUrl: type: string format: uri pattern: "^[Hh][Tt][Tt][Pp][Ss]:[/][/]" maxLength: 2048 description: HTTPS link to the operator's privacy notice. tosUrl: type: string format: uri pattern: "^[Hh][Tt][Tt][Pp][Ss]:[/][/]" maxLength: 2048 description: HTTPS link to the operator's terms and conditions of use. Address: type: object additionalProperties: false required: - street - city - state - postalCode - country properties: street: type: string maxLength: 512 city: type: string maxLength: 64 state: type: string maxLength: 64 postalCode: type: string maxLength: 64 country: type: string maxLength: 64 SupportContactCreateRequest: type: object additionalProperties: false required: - type - value properties: type: type: string enum: - email - phone - website value: type: string maxLength: 2048 SupportContactResponse: type: object additionalProperties: false required: - id - type - value properties: id: type: string pattern: "^[0-9A-HJKMNP-TV-Z]{26}$" type: type: string enum: - email - phone - website value: type: string maxLength: 2048 Website: type: object additionalProperties: false required: - url properties: url: type: string format: uri maxLength: 2048 OpportunityCreateRequest: type: object additionalProperties: false required: - dateFrom - beneficiaryBenefit - localizedMetadata - categoryId properties: dateFrom: type: string format: date dateTo: type: string format: date url: type: string format: uri maxLength: 2048 categoryId: type: string pattern: "^[0-9A-HJKMNP-TV-Z]{26}$" nationalTerritory: type: boolean default: false placeIds: type: array minItems: 0 items: type: string pattern: "^[0-9A-HJKMNP-TV-Z]{26}$" beneficiaryBenefit: $ref: "#/components/schemas/BenefitRequest" caregiverBenefit: $ref: "#/components/schemas/BenefitRequest" localizedMetadata: type: array minItems: 1 items: $ref: "#/components/schemas/LocalizedMetadataItem" OpportunityUpdateRequest: type: object additionalProperties: false description: >- Full replacement of the writable opportunity representation. All required writable fields must be sent on every request. Omitting an optional dateTo, url, or caregiverBenefit field clears its current value. Null values are not accepted. required: - updatedAt - dateFrom - categoryId - nationalTerritory - placeIds - beneficiaryBenefit - localizedMetadata properties: updatedAt: type: string format: date-time description: >- Value previously read from the opportunity, echoed back for optimistic-concurrency control. A stale value yields 409. dateFrom: type: string format: date dateTo: type: string format: date url: type: string format: uri maxLength: 2048 categoryId: type: string pattern: "^[0-9A-HJKMNP-TV-Z]{26}$" nationalTerritory: type: boolean placeIds: type: array minItems: 0 items: type: string pattern: "^[0-9A-HJKMNP-TV-Z]{26}$" beneficiaryBenefit: $ref: "#/components/schemas/BenefitRequest" caregiverBenefit: $ref: "#/components/schemas/BenefitRequest" localizedMetadata: type: array minItems: 1 items: $ref: "#/components/schemas/LocalizedMetadataItem" BenefitRequest: oneOf: - $ref: "#/components/schemas/BenefitFree" - $ref: "#/components/schemas/BenefitPriority" - $ref: "#/components/schemas/BenefitReducedFixedPrice" - $ref: "#/components/schemas/BenefitDiscount" - $ref: "#/components/schemas/BenefitOther" discriminator: propertyName: type mapping: free: "#/components/schemas/BenefitFree" priority: "#/components/schemas/BenefitPriority" reduced_fixed_price: "#/components/schemas/BenefitReducedFixedPrice" discount: "#/components/schemas/BenefitDiscount" other: "#/components/schemas/BenefitOther" BenefitFree: type: object additionalProperties: false required: - type properties: type: type: string enum: - free BenefitPriority: type: object additionalProperties: false required: - type properties: type: type: string enum: - priority BenefitReducedFixedPrice: type: object additionalProperties: false required: - type - value properties: type: type: string enum: - reduced_fixed_price value: type: integer BenefitDiscount: type: object additionalProperties: false required: - type - discountType - value properties: type: type: string enum: - discount discountType: type: string enum: - percentage - fixed_amount value: type: integer BenefitOther: type: object additionalProperties: false required: - type - description properties: type: type: string enum: - other description: type: string maxLength: 4096 LocalizedMetadataItem: type: object additionalProperties: false required: - key - language - value properties: key: type: string enum: - name - description - condition language: type: string enum: - en - fr - de - sl - it value: type: string OpportunityListResponse: type: object additionalProperties: false required: - items - total properties: items: type: array items: $ref: "#/components/schemas/OpportunitySummaryItem" total: type: integer minimum: 0 AdminOpportunityListResponse: type: object additionalProperties: false required: - items - total properties: items: type: array items: $ref: "#/components/schemas/AdminOpportunitySummaryItem" total: type: integer minimum: 0 OpportunitySummaryItem: type: object additionalProperties: false required: - id - status - name - categoryTitle - dateFrom properties: id: type: string pattern: "^[0-9A-HJKMNP-TV-Z]{26}$" status: type: string enum: - draft - test_pending - test_rejected - test_passed - published - scheduled - scheduled_suspension - suspended - deleted name: type: string categoryTitle: type: string dateFrom: type: string format: date dateTo: type: string format: date nullable: true suspendedBy: type: string enum: - operator - department nullable: true description: >- Actor type that suspended the opportunity (operator or department). null when neither suspended nor scheduled for suspension. suspendFrom: type: string format: date nullable: true description: >- Calendar date a scheduled suspension takes effect from. Present only while a suspension is scheduled (opportunity still published); null otherwise. republishMessage: type: string maxLength: 4096 nullable: true description: >- Reason the operator gave asking for the opportunity to be republished, while the request is pending. Only set while the opportunity is suspended; null otherwise. republishRejectionMessage: type: string maxLength: 4096 nullable: true description: >- Reason the department rejected the last republish request. Only set while the opportunity is suspended; null otherwise. AdminOpportunitySummaryItem: type: object additionalProperties: false required: - id - status - name - categoryTitle - dateFrom - operatorName properties: id: type: string pattern: "^[0-9A-HJKMNP-TV-Z]{26}$" status: type: string enum: - draft - test_pending - test_rejected - test_passed - published - scheduled - scheduled_suspension - suspended - deleted name: type: string categoryTitle: type: string dateFrom: type: string format: date dateTo: type: string format: date nullable: true operatorName: type: string deletionMessage: type: string maxLength: 4096 nullable: true description: >- Reason the opportunity was deleted (raw text). Present only for opportunities deleted from a suspended state; null otherwise. Exposed to department/admin only. suspendedBy: type: string enum: - operator - department nullable: true description: >- Actor type that suspended the opportunity (operator or department). null when neither suspended nor scheduled for suspension. suspendFrom: type: string format: date nullable: true description: >- Calendar date a scheduled suspension takes effect from. Present only while a suspension is scheduled (opportunity still published); null otherwise. republishMessage: type: string maxLength: 4096 nullable: true description: >- Reason the operator gave asking for the opportunity to be republished, while the request is pending. Only set while the opportunity is suspended; null otherwise. republishRejectionMessage: type: string maxLength: 4096 nullable: true description: >- Reason the department rejected the last republish request. Only set while the opportunity is suspended; null otherwise. OpportunityDetailResponse: type: object additionalProperties: false required: - id - status - dateFrom - categoryId - categoryTitle - nationalTerritory - beneficiaryBenefit - localizedMetadata - placeIds - createdAt - updatedAt properties: id: type: string pattern: "^[0-9A-HJKMNP-TV-Z]{26}$" status: type: string enum: - draft - test_pending - test_rejected - test_passed - published - scheduled - scheduled_suspension - suspended - deleted dateFrom: type: string format: date dateTo: type: string format: date nullable: true url: type: string format: uri maxLength: 2048 nullable: true nationalTerritory: type: boolean categoryId: type: string pattern: "^[0-9A-HJKMNP-TV-Z]{26}$" categoryTitle: type: string beneficiaryBenefit: $ref: "#/components/schemas/BenefitRequest" caregiverBenefit: nullable: true allOf: - $ref: "#/components/schemas/BenefitRequest" localizedMetadata: type: array items: $ref: "#/components/schemas/LocalizedMetadataItem" placeIds: type: array items: type: string pattern: "^[0-9A-HJKMNP-TV-Z]{26}$" createdAt: type: string format: date-time updatedAt: type: string format: date-time suspendedBy: type: string enum: - operator - department nullable: true description: >- Actor type that suspended the opportunity (operator or department). null when neither suspended nor scheduled for suspension. suspendFrom: type: string format: date nullable: true description: >- Calendar date a scheduled suspension takes effect from. Present only while a suspension is scheduled (opportunity still published); null otherwise. suspensionMessage: type: string maxLength: 4096 nullable: true description: >- Reason provided for the suspension (raw text). null when not suspended. changeRequestMessage: type: string maxLength: 4096 nullable: true description: >- Changes the department asked the operator to make on the last review cycle (raw text). null when no change was ever requested. republishMessage: type: string maxLength: 4096 nullable: true description: >- Reason the operator gave asking for the opportunity to be republished, while the request is pending. Only set while the opportunity is suspended; null otherwise. republishRejectionMessage: type: string maxLength: 4096 nullable: true description: >- Reason the department rejected the last republish request. Only set while the opportunity is suspended; null otherwise. OpportunityDetailAdminResponse: type: object additionalProperties: false required: - id - status - dateFrom - categoryId - categoryTitle - beneficiaryBenefit - localizedMetadata - placeIds - createdAt - updatedAt properties: id: type: string pattern: "^[0-9A-HJKMNP-TV-Z]{26}$" status: type: string enum: - draft - test_pending - test_rejected - test_passed - published - scheduled - scheduled_suspension - suspended - deleted dateFrom: type: string format: date dateTo: type: string format: date nullable: true url: type: string format: uri nullable: true categoryId: type: string pattern: "^[0-9A-HJKMNP-TV-Z]{26}$" categoryTitle: type: string beneficiaryBenefit: $ref: "#/components/schemas/BenefitRequest" caregiverBenefit: nullable: true allOf: - $ref: "#/components/schemas/BenefitRequest" localizedMetadata: type: array items: $ref: "#/components/schemas/LocalizedMetadataItem" placeIds: type: array items: type: string pattern: "^[0-9A-HJKMNP-TV-Z]{26}$" createdAt: type: string format: date-time updatedAt: type: string format: date-time operatorName: type: string deletionMessage: type: string maxLength: 4096 nullable: true description: >- Reason the opportunity was deleted (raw text). Present only for opportunities deleted from a suspended state; null otherwise. Exposed to department/admin only. suspendedBy: type: string enum: - operator - department nullable: true description: >- Actor type that suspended the opportunity (operator or department). null when neither suspended nor scheduled for suspension. suspendFrom: type: string format: date nullable: true description: >- Calendar date a scheduled suspension takes effect from. Present only while a suspension is scheduled (opportunity still published); null otherwise. suspensionMessage: type: string maxLength: 4096 nullable: true description: >- Reason provided for the suspension (raw text). null when not suspended. changeRequestMessage: type: string maxLength: 4096 nullable: true description: >- Changes the department asked the operator to make on the last review cycle (raw text). null when no change was ever requested. republishMessage: type: string maxLength: 4096 nullable: true description: >- Reason the operator gave asking for the opportunity to be republished, while the request is pending. Only set while the opportunity is suspended; null otherwise. republishRejectionMessage: type: string maxLength: 4096 nullable: true description: >- Reason the department rejected the last republish request. Only set while the opportunity is suspended; null otherwise. ErrorResponse: type: object additionalProperties: false required: - statusCode - message properties: statusCode: type: integer message: type: string OpportunityCategoryItem: type: object additionalProperties: false required: - id - title - description properties: id: type: string pattern: "^[0-9A-HJKMNP-TV-Z]{26}$" title: type: string description: type: string AuthorizeResponse: type: object additionalProperties: false required: - first_name - last_name - operator_name - session_token - user_type properties: first_name: type: string last_name: type: string operator_name: type: string session_token: type: string user_type: type: string enum: - admin - operator - test_admin - test_operator PendingOnboardingsResponse: type: object required: - items - count properties: items: type: array items: $ref: "#/components/schemas/OnboardingItem" count: type: integer minimum: 0 OnboardingItem: type: object properties: id: type: string productId: type: string workflowType: type: string status: type: string city: type: string county: type: string createdAt: type: string format: date-time updatedAt: type: string format: date-time opportunityCount: type: integer minimum: 0 description: >- Number of opportunities for this operator. Present only for non-PENDING_IN_REVIEW onboardings. institution: type: object properties: id: type: string description: type: string taxCode: type: string digitalAddress: type: string city: type: string county: type: string OnboardingGeographicTaxonomy: type: object properties: code: type: string desc: type: string OnboardingPaymentServiceProvider: type: object properties: businessRegisterNumber: type: string legalRegisterNumber: type: string legalRegisterName: type: string longTermPayments: type: boolean abiCode: type: string vatNumberGroup: type: boolean providerNames: type: array items: type: string contractType: type: string contractId: type: string OnboardingDataProtectionOfficer: type: object properties: address: type: string email: type: string pec: type: string OnboardingInstitutionDetail: type: object properties: id: type: string institutionType: type: string taxCode: type: string taxCodeInvoicing: type: string subunitCode: type: string subunitType: type: string origin: type: string originId: type: string city: type: string country: type: string county: type: string description: type: string digitalAddress: type: string address: type: string zipCode: type: string parentDescription: type: string geographicTaxonomies: type: array items: $ref: "#/components/schemas/OnboardingGeographicTaxonomy" rea: type: string shareCapital: type: string businessRegisterPlace: type: string supportEmail: type: string supportPhone: type: string paymentServiceProvider: $ref: "#/components/schemas/OnboardingPaymentServiceProvider" dataProtectionOfficer: $ref: "#/components/schemas/OnboardingDataProtectionOfficer" atecoCodes: type: array items: type: string legalForm: type: string OnboardingUser: type: object properties: id: type: string taxCode: type: string name: type: string surname: type: string email: type: string role: type: string productRole: type: string OnboardingBilling: type: object properties: vatNumber: type: string recipientCode: type: string publicServices: type: boolean OnboardingPayment: type: object properties: iban: type: string holder: type: string OnboardingAdditionalInformations: type: object properties: belongRegulatedMarket: type: boolean regulatedMarketNote: type: string ipa: type: boolean ipaCode: type: string establishedByRegulatoryProvision: type: boolean establishedByRegulatoryProvisionNote: type: string agentOfPublicService: type: boolean agentOfPublicServiceNote: type: string otherNote: type: string OnboardingUserRequester: type: object properties: userMailUuid: type: string userRequestUid: type: string OnboardingDetail: type: object properties: id: type: string productId: type: string workflowType: type: string institution: $ref: "#/components/schemas/OnboardingInstitutionDetail" users: type: array items: $ref: "#/components/schemas/OnboardingUser" pricingPlan: type: string billing: $ref: "#/components/schemas/OnboardingBilling" payment: $ref: "#/components/schemas/OnboardingPayment" signContract: type: boolean additionalInformations: $ref: "#/components/schemas/OnboardingAdditionalInformations" createdAt: type: string format: date-time updatedAt: type: string format: date-time expiringDate: type: string format: date-time activatedAt: type: string format: date-time status: type: string userRequester: $ref: "#/components/schemas/OnboardingUserRequester" reasonForReject: type: string attachments: type: array items: type: string