{
  "openapi": "3.0.3",
  "info": {
    "title": "SupportHub Ticketing APIs",
    "version": "1.0",
    "description": "REST API for creating and managing SupportHub tickets, intended for the Partner.\n\n## Authentication\n\nEach call requires a JWT OAuth 2.0 (Bearer) token obtained from **Microsoft Entra ID** using the `client_credentials` flow.\n\n```\nPOST https://login.microsoftonline.com/{tenantId}/oauth2/v2.0/token\nContent-Type: application/x-www-form-urlencoded\n\ngrant_type=client_credentials\nclient_id={CLIENT_ID}\nclient_secret={CLIENT_SECRET}\nscope=https://service.flow.microsoft.com//.default\n```\n\n**Tenant ID:** `{tenantId}`\n\nThe token is valid for ~1 hour (`expires_in: 3599`). Renew it before expiration.\n\n## Required headers\n\n- `Authorization`: required on all endpoints; value format `Bearer {access_token}`.\n\n## Data format\n\n- All dates are in **UTC ISO 8601** with `Z` suffix (e.g. `2025-10-21T14:12:44Z`).\n- `Status` values in JSON payloads include a space (e.g. `In progress`); in path/query URL use the compact form (e.g. `InProgress`).\n- The `description` and `closingResponse` fields must not contain unsafe HTML tags (script, iframe, PHP)."
  },
  "servers": [
    {
      "url": "https://sh-qa.flowe.com/backoffice",
      "description": "QA / Test"
    },
    {
      "url": "https://sh.flowe.com/backoffice",
      "description": "Production"
    }
  ],
  "security": [
    {
      "oauth2": ["https://service.flow.microsoft.com//.default"]
    }
  ],
  "tags": [
    {
      "name": "Tickets",
      "description": "Create, read and update operations for SupportHub tickets"
    }
  ],
  "components": {
    "securitySchemes": {
      "oauth2": {
        "type": "oauth2",
        "description": "OAuth 2.0 with Microsoft Entra ID. For machine-to-machine (M2M) integrations use the `clientCredentials` flow.",
        "flows": {
          "clientCredentials": {
            "tokenUrl": "https://login.microsoftonline.com/{tenantId}/oauth2/v2.0/token",
            "scopes": {
              "https://service.flow.microsoft.com//.default": "Access to SupportHub APIs (machine-to-machine, client credentials)"
            }
          },
          "authorizationCode": {
            "authorizationUrl": "https://login.microsoftonline.com/{tenantId}/oauth2/v2.0/authorize",
            "tokenUrl": "https://login.microsoftonline.com/{tenantId}/oauth2/v2.0/token",
            "scopes": {
              "user_impersonation": "Access SupportHub APIs with the user's identity"
            }
          }
        }
      }
    },
    "parameters": {
      "CaseNumberPath": {
        "name": "casenumber",
        "in": "path",
        "required": true,
        "description": "Unique ticket identifier (e.g. `TK-000001234`).",
        "schema": {
          "type": "string",
          "example": "TK-000001234"
        }
      },
      "PageQuery": {
        "name": "page",
        "in": "query",
        "required": false,
        "description": "0-based page number. Page size is 10 tickets.",
        "schema": {
          "type": "integer",
          "format": "int32",
          "minimum": 0,
          "default": 0,
          "example": 0
        }
      }
    },
    "responses": {
      "Error400": {
        "description": "Malformed request (e.g. URL parameter with spaces or invalid format).",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "error": "Bad Request",
              "error_description": "Status parameter format is invalid."
            }
          }
        }
      },
      "Error404": {
        "description": "Resource not found or not belonging to the authenticated partner.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "error": "Not Found",
              "error_description": "Ticket TK-000001234 Not Found."
            }
          }
        }
      },
      "Error422": {
        "description": "Validation failed: missing field, invalid value, disallowed status transition, or unsafe content.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "error": "Unprocessable Entity",
              "error_description": "Description parameter is missing."
            }
          }
        }
      }
    },
    "schemas": {
      "TicketStatus": {
        "type": "string",
        "description": "Ticket status as shown in JSON response payloads. The `In progress` value contains a space; in path/query URL use `InProgress` (no spaces).",
        "enum": [
          "New",
          "In progress",
          "WaitingForCustomer",
          "Resolved",
          "Closed",
          "Canceled",
          "Rejected"
        ],
        "example": "New"
      },
      "TicketStatusUrl": {
        "type": "string",
        "description": "Ticket status as used in path URLs and query parameters (no spaces, system is case-insensitive).",
        "enum": [
          "New",
          "InProgress",
          "WaitingForCustomer",
          "Resolved",
          "Closed",
          "Canceled",
          "Rejected"
        ],
        "example": "InProgress"
      },
      "Error": {
        "type": "object",
        "required": ["error", "error_description"],
        "properties": {
          "error": {
            "type": "string",
            "description": "Type of HTTP error.",
            "example": "Unprocessable Entity"
          },
          "error_description": {
            "type": "string",
            "description": "Detailed description of the problem.",
            "example": "Description parameter is missing."
          }
        }
      },
      "CreateTicketRequest": {
        "type": "object",
        "required": ["type", "description", "category"],
        "description": "Request body for ticket creation.",
        "properties": {
          "walletid": {
            "type": "string",
            "nullable": true,
            "description": "Unique identifier of the involved wallet. **Required** if `type` is `Consumer`. Do not set for `Alert` and `Business`.",
            "example": "19c57d27-8fc7-4dec-afe0-5023488df4b9"
          },
          "externalid": {
            "type": "string",
            "nullable": true,
            "description": "Report ID in the Partner's internal system. Used to correlate the SupportHub ticket with the Partner systems.",
            "example": "EXT-1938880"
          },
          "type": {
            "type": "string",
            "description": "Nature of the report:\n- `Consumer` � report about an end customer (wallet); requires `walletid`\n- `Alert` � widespread service unavailability (priority 0); use `category: \"Indisponibilit� del servizio\"`\n- `Business` � B2B issues; use `category: \"Segnalazioni B2B\"`",
            "enum": ["Consumer", "Alert", "Business"],
            "example": "Consumer"
          },
          "category": {
            "type": "string",
            "description": "Report category. For `type: Business` the only allowed value is `Segnalazioni B2B`. For `type: Alert` use `Indisponibilit� del servizio`.",
            "enum": [
              "Saldo non aggiornato",
              "Ricarica non visibile",
              "Ricarica SCT/CASH non visibile",
              "Ricarica welfare",
              "Altri problemi sui pagamenti",
              "Rimborso cash",
              "SDD",
              "Validazione IBAN",
              "Registrazione servizio",
              "Chiusura wallet",
              "Indisponibilit� del servizio",
              "Segnalazioni B2B",
              "Altro"
            ],
            "example": "Saldo non aggiornato"
          },
          "title": {
            "type": "string",
            "nullable": true,
            "description": "Descriptive title of the ticket (optional).",
            "example": "Balance not updated for 3 days"
          },
          "description": {
            "type": "string",
            "description": "Detailed description of the issue. Must not contain unsafe HTML tags (script, iframe, PHP).",
            "example": "The wallet balance has not updated for 3 days despite performed top-ups."
          }
        }
      },
      "CreateTicketResponse": {
        "type": "object",
        "properties": {
          "Response": {
            "type": "object",
            "properties": {
              "message": {
                "type": "string",
                "example": "Ticket created successfully."
              },
              "caseNumber": {
                "type": "string",
                "description": "Unique identifier of the ticket created in SupportHub. Keep it for subsequent operations.",
                "example": "TK-000001234"
              }
            }
          }
        }
      },
      "PostCommentRequest": {
        "type": "object",
        "required": ["text"],
        "properties": {
          "text": {
            "type": "string",
            "description": "Comment text. If the ticket is in `WaitingForCustomer` state, the call automatically updates the status to `In progress` and recalculates the SLA Validity Date.",
            "example": "I update the report with additional information."
          }
        }
      },
      "PostCommentResponse": {
        "type": "object",
        "properties": {
          "response": {
            "type": "string",
            "example": "OK"
          }
        }
      },
      "TicketSummary": {
        "type": "object",
        "description": "Ticket summary (used in list responses).",
        "properties": {
          "casenumber": {
            "type": "string",
            "description": "Unique ticket identifier.",
            "example": "TK-000001286"
          },
          "externalID": {
            "type": "string",
            "nullable": true,
            "description": "Partner internal ID.",
            "example": "EXT-1234"
          },
          "type": {
            "type": "string",
            "description": "Ticket type (`Wallet` or `Management`).",
            "example": "Consumer"
          },
          "walletID": {
            "type": "string",
            "nullable": true,
            "example": "19c57d27-8fc7-4dec-afe0-5023488df4b9"
          },
          "subject": {
            "type": "string",
            "nullable": true,
            "description": "Ticket subject/title.",
            "example": null
          },
          "status": {
            "$ref": "#/components/schemas/TicketStatus"
          },
          "creationDate": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "Ticket opening date/time (UTC ISO 8601).",
            "example": "2025-10-21T14:12:44Z"
          },
          "closureDate": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "Closure date/time. Set when status is `Closed` or `Canceled` (UTC ISO 8601).",
            "example": null
          },
          "closureResponse": {
            "type": "string",
            "nullable": true,
            "description": "Closing response provided by the Partner.",
            "example": null
          },
          "priority": {
            "type": "string",
            "nullable": true,
            "description": "Ticket priority (e.g. `1` = highest).",
            "example": null
          },
          "takenInChargeOn": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "Date/time when the ticket was taken in charge (set in case of service unavailability).",
            "example": null
          }
        }
      },
      "GetPartnerTicketsResponse": {
        "type": "object",
        "properties": {
          "response": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TicketSummary"
            }
          }
        }
      },
      "TicketDetail": {
        "type": "object",
        "description": "Full detail of a ticket.",
        "properties": {
          "casenumber": {
            "type": "string",
            "description": "Unique ticket identifier.",
            "example": "TK-000001165"
          },
          "externalID": {
            "type": "string",
            "nullable": true,
            "description": "Partner internal ID.",
            "example": "EXT-1234"
          },
          "type": {
            "type": "string",
            "description": "Ticket type (`Wallet` or `Management`).",
            "example": "Wallet"
          },
          "walletID": {
            "type": "string",
            "nullable": true,
            "example": "19c57d27-8fc7-4dec-afe0-5023488df4b9"
          },
          "subject": {
            "type": "string",
            "nullable": true,
            "description": "Ticket subject/title.",
            "example": null
          },
          "status": {
            "$ref": "#/components/schemas/TicketStatus"
          },
          "partner": {
            "type": "string",
            "description": "Code/name of the partner owning the ticket.",
            "example": "Mooney"
          },
          "openingDate": {
            "type": "string",
            "format": "date-time",
            "description": "Ticket opening date/time (UTC ISO 8601).",
            "example": "2025-10-21T14:12:44Z"
          },
          "expirationDate": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "Ticket SLA expiration date/time (UTC ISO 8601). Can be recalculated by PostComment if the ticket was in `WaitingForCustomer` state.",
            "example": "2025-10-23T09:00:00Z"
          },
          "resolvedDate": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "Resolution date/time. Set when status becomes `Resolved` (UTC ISO 8601).",
            "example": null
          },
          "closureDate": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "Closure date/time. Set when status is `Closed` or `Canceled` (UTC ISO 8601).",
            "example": null
          },
          "closureResponse": {
            "type": "string",
            "nullable": true,
            "description": "Closing response provided by the Partner for the `Resolved` ? `Closed` transition.",
            "example": null
          },
          "priority": {
            "type": "string",
            "nullable": true,
            "description": "Ticket priority (e.g. `1` = highest).",
            "example": null
          },
          "takenInChargeOn": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "Date/time when the ticket was taken in charge (set in case of service unavailability).",
            "example": null
          }
        }
      },
      "GetTicketResponse": {
        "type": "object",
        "properties": {
          "response": {
            "$ref": "#/components/schemas/TicketDetail"
          }
        }
      },
      "GetTicketsByWalletIDResponse": {
        "type": "object",
        "properties": {
          "response": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TicketSummary"
            }
          }
        }
      },
      "TimelineItem": {
        "type": "object",
        "description": "Single timeline entry for a ticket.",
        "properties": {
          "createdby": {
            "type": "string",
            "description": "Event author:\n- Partner username for manual actions\n- `SystemDaemon` for automated actions (e.g. status change `WaitingForCustomer` ? `In progress` after PostComment)\n- `PowerPlatform Tech User` as visible author for internal automatic actions",
            "example": "[Partner] User"
          },
          "createdon": {
            "type": "string",
            "format": "date-time",
            "description": "Event date/time (UTC ISO 8601).",
            "example": "2024-04-29T09:09:29Z"
          },
          "text": {
            "type": "string",
            "description": "Comment text or event description (e.g. `[Partner] User changed status from [New] to [Canceled]`).",
            "example": "[Partner]: test"
          }
        }
      },
      "GetTicketTimelineResponse": {
        "type": "object",
        "properties": {
          "response": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TimelineItem"
            }
          }
        }
      },
      "UpdateStatusRequest": {
        "type": "object",
        "description": "Request body for updating the status via path.\n\n**Allowed transitions for the Partner:**\n- `New` -> `Canceled`\n- `InProgress` -> `Canceled`\n- `WaitingForCustomer` -> `Canceled`\n- `Resolved` -> `Closed` (`closingResponse` is required)",
        "properties": {
          "closingResponse": {
            "type": "string",
            "nullable": true,
            "description": "Closing response/reason. **Required** for the `Resolved` ? `Closed` transition. Must not contain script, iframe or PHP.",
            "example": "I confirm the resolution of the reported issue."
          }
        }
      },
      "UpdateStatusBodyRequest": {
        "type": "object",
        "required": ["status"],
        "description": "Request body for updating the status via body.\n\n**Allowed transitions for the Partner:**\n- `New` -> `Canceled`\n- `InProgress` -> `Canceled`\n- `WaitingForCustomer` -> `Canceled`\n- `Resolved` -> `Closed` (`closingResponse` is required)",
        "properties": {
          "status": {
            "$ref": "#/components/schemas/TicketStatusUrl"
          },
          "closingResponse": {
            "type": "string",
            "nullable": true,
            "description": "Closing response/reason. **Required** for the `Resolved` ? `Closed` transition. Must not contain script, iframe or PHP.",
            "example": "I confirm the resolution of the reported issue."
          }
        }
      },
      "UpdateStatusResponse": {
        "type": "object",
        "properties": {
          "Response": {
            "type": "string",
            "example": "OK"
          }
        }
      },
      "ErrorResponse": {
        "type": "object",
        "properties": {
          "error": { "type": "string" },
          "error_description": { "type": "string" }
        },
        "required": ["error", "error_description"]
      },
      "Attachment": {
        "type": "object",
        "properties": {
          "id": { "type": "integer" },
          "filename": { "type": "string" },
          "createdOn": { "type": "string", "format": "date-time" },
          "contentType": { "type": "string" },
          "filecontent": { "type": "string", "description": "base64 content when present" }
        }
      },
      "AttachmentList": {
        "type": "object",
        "properties": {
          "response": {
            "type": "array",
            "items": { "$ref": "#/components/schemas/Attachment" }
          }
        }
      },
      "UploadAttachmentResponse": {
        "type": "object",
        "properties": {
          "message": { "type": "string" },
          "id": { "type": "integer" },
          "caseNumber": { "type": "string" },
          "filename": { "type": "string" }
        }
      },
      "GetAttachmentResponse": {
        "type": "object",
        "properties": {
          "response": { "$ref": "#/components/schemas/Attachment" }
        }
      }
    }
  },
  "paths": {
    "/tickets": {
      "post": {
        "tags": ["Tickets"],
        "operationId": "CreateTicket",
        "summary": "Create a ticket",
        "description": "Opens a new report in SupportHub. Returns the unique `caseNumber` to be used in subsequent calls.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/CreateTicketRequest" }
            }
          }
        },
        "responses": {
          "200": { "description": "Ticket created successfully.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreateTicketResponse" } } } },
          "404": { "description": "Wallet not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
          "422": { "description": "Validation failed.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }
        },
        "security": [{ "oauth2": ["https://service.flow.microsoft.com//.default"] }]
      }
    },
    "/tickets/{casenumber}/comments": {
      "post": {
        "tags": ["Tickets"],
        "operationId": "PostComment",
        "summary": "Add a comment to a ticket",
        "description": "Adds a textual comment to the timeline of an existing ticket.",
        "parameters": [{ "$ref": "#/components/parameters/CaseNumberPath" }],
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PostCommentRequest" } } } },
        "responses": {
          "200": { "description": "Comment added successfully.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PostCommentResponse" } } } },
          "404": { "$ref": "#/components/responses/Error404" }
        },
        "security": [{ "oauth2": ["https://service.flow.microsoft.com//.default"] }]
      }
    },
    "/tickets/list/{status}": {
      "get": {
        "tags": ["Tickets"],
        "operationId": "GetPartnerTickets",
        "summary": "Partner tickets list",
        "description": "Returns the paginated list (10 tickets per page) of the Partner's tickets filtered by status and optionally by type.",
        "parameters": [
          { "name": "status", "in": "path", "required": true, "schema": { "$ref": "#/components/schemas/TicketStatusUrl" } },
          { "name": "type", "in": "query", "required": false, "schema": { "type": "string", "enum": ["Management", "Wallet"] } },
          { "$ref": "#/components/parameters/PageQuery" }
        ],
        "responses": {
          "200": { "description": "List of tickets.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/GetPartnerTicketsResponse" } } } },
          "400": { "$ref": "#/components/responses/Error400" },
          "404": { "description": "Not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }
        },
        "security": [{ "oauth2": ["https://service.flow.microsoft.com//.default"] }]
      }
    },
    "/tickets/{casenumber}": {
      "get": {
        "tags": ["Tickets"],
        "operationId": "GetTicket",
        "summary": "Ticket detail",
        "description": "Returns the full detail of a ticket by its `caseNumber`.",
        "parameters": [{ "$ref": "#/components/parameters/CaseNumberPath" }],
        "responses": {
          "200": { "description": "Ticket detail.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/GetTicketResponse" } } } },
          "404": { "$ref": "#/components/responses/Error404" }
        },
        "security": [{ "oauth2": ["https://service.flow.microsoft.com//.default"] }]
      }
    },
    "/tickets/wallet/{walletid}": {
      "get": {
        "tags": ["Tickets"],
        "operationId": "GetTicketsByWalletID",
        "summary": "Tickets by Wallet",
        "description": "Returns all tickets associated with a specific wallet.",
        "parameters": [{ "name": "walletid", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } }],
        "responses": {
          "200": { "description": "List of tickets associated with the wallet.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/GetTicketsByWalletIDResponse" } } } },
          "404": { "$ref": "#/components/responses/Error404" }
        },
        "security": [{ "oauth2": ["https://service.flow.microsoft.com//.default"] }]
      }
    },
    "/tickets/{casenumber}/timeline": {
      "get": {
        "tags": ["Tickets"],
        "operationId": "GetTicketTimeline",
        "summary": "Ticket timeline",
        "description": "Returns the chronological sequence of all events, comments and status changes of a ticket.",
        "parameters": [{ "$ref": "#/components/parameters/CaseNumberPath" }],
        "responses": {
          "200": { "description": "Ticket timeline in chronological order.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/GetTicketTimelineResponse" } } } },
          "404": { "$ref": "#/components/responses/Error404" }
        },
        "security": [{ "oauth2": ["https://service.flow.microsoft.com//.default"] }]
      }
    },
    "/tickets/{casenumber}/{newStatus}": {
      "put": {
        "tags": ["Tickets"],
        "operationId": "UpdateTicketStatusPath",
        "summary": "Update ticket status (status via path)",
        "description": "Updates the ticket status by passing the new status as a path parameter in the URL.",
        "parameters": [
          { "$ref": "#/components/parameters/CaseNumberPath" },
          { "name": "newStatus", "in": "path", "required": true, "schema": { "$ref": "#/components/schemas/TicketStatusUrl" } }
        ],
        "requestBody": { "required": false, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UpdateStatusRequest" } } } },
        "responses": {
          "200": { "description": "Status updated successfully.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UpdateStatusResponse" } } } },
          "404": { "$ref": "#/components/responses/Error404" },
          "422": { "description": "Unprocessable", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }
        },
        "security": [{ "oauth2": ["https://service.flow.microsoft.com//.default"] }]
      }
    },
    "/tickets/{casenumber}/Status": {
      "put": {
        "tags": ["Tickets"],
        "operationId": "UpdateTicketStatusBody",
        "summary": "Update ticket status (status via body)",
        "description": "Alternative variant for status update.",
        "parameters": [{ "$ref": "#/components/parameters/CaseNumberPath" }],
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UpdateStatusBodyRequest" } } } },
        "responses": {
          "200": { "description": "Status updated successfully.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UpdateStatusResponse" } } } },
          "404": { "$ref": "#/components/responses/Error404" },
          "422": { "description": "Unprocessable", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }
        },
        "security": [{ "oauth2": ["https://service.flow.microsoft.com//.default"] }]
      }
    },
    "/tickets/{casenumber}/attachments": {
      "get": {
        "tags": ["Tickets"],
        "operationId": "GetTicketAttachments",
        "summary": "List ticket attachments",
        "description": "Returns attachment metadata.",
        "parameters": [{ "$ref": "#/components/parameters/CaseNumberPath" }],
        "responses": {
          "200": { "description": "Attachment list.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AttachmentList" } } } },
          "404": { "description": "Ticket not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } },
          "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } }
        },
        "security": [{ "oauth2": ["https://service.flow.microsoft.com//.default"] }]
      },
      "post": {
        "tags": ["Tickets"],
        "operationId": "PostAttachment",
        "summary": "Upload an attachment",
        "description": "Uploads a binary file to an existing ticket.",
        "parameters": [
          { "$ref": "#/components/parameters/CaseNumberPath" },
          { "name": "filename", "in": "query", "required": true, "schema": { "type": "string" } }
        ],
        "requestBody": { "required": true, "content": { "application/octet-stream": { "schema": { "type": "string", "format": "binary" } } } },
        "responses": {
          "200": { "description": "Attachment uploaded successfully.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UploadAttachmentResponse" } } } },
          "400": { "description": "Missing or invalid parameters.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } },
          "404": { "description": "Ticket not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } },
          "409": { "description": "Ticket closed or canceled.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } },
          "413": { "description": "File too large.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } },
          "415": { "description": "Unsupported file type.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } },
          "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } }
        },
        "security": [{ "oauth2": ["https://service.flow.microsoft.com//.default"] }]
      }
    },
    "/tickets/{casenumber}/attachments/{attachmentid}": {
      "get": {
        "tags": ["Tickets"],
        "operationId": "GetAttachment",
        "summary": "Get attachment",
        "description": "Returns a single attachment.",
        "parameters": [
          { "$ref": "#/components/parameters/CaseNumberPath" },
          { "name": "attachmentid", "in": "path", "required": true, "schema": { "type": "integer" } }
        ],
        "responses": {
          "200": { "description": "Attachment detail.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/GetAttachmentResponse" } } } },
          "404": { "description": "Ticket or attachment not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } },
          "500": { "description": "Internal server error.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } }
        },
        "security": [{ "oauth2": ["https://service.flow.microsoft.com//.default"] }]
      }
    }
  }
}