{
  "openapi": "3.0.1",
  "info": {
    "title": "Wassa Innovation Services API",
    "version": "1.0.0",
    "description": "API documentation for Wassa Innovation Services (WIS) platform. ## Authentication Authentication is made with the login route using `clientId` and `secretId`. It returns a token needed for all other routes. - Login route: No Auth - All other routes: Bearer Token"
  },
  "servers": [
    {
      "url": "https://api.services.wassa.io"
    }
  ],
  "security": [
    {
      "bearerAuth": []
    }
  ],
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "JWT",
        "description": "JWT token needed for all other routes. The token acquired with the login route."
      }
    },
    "schemas": {
      "LoginRequest": {
        "type": "object",
        "required": [
          "clientId",
          "secretId"
        ],
        "properties": {
          "clientId": {
            "type": "string",
            "description": "Client Id available in the Developer Account section",
            "example": "client_123456789"
          },
          "secretId": {
            "type": "string",
            "description": "Secret ID available in the Developer Account section",
            "example": "secret_987654321"
          }
        }
      },
      "LoginResponse": {
        "type": "object",
        "required": [
          "token",
          "refreshToken",
          "expiresIn"
        ],
        "properties": {
          "token": {
            "type": "string",
            "description": "JWT token for authentication",
            "example": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
          },
          "refreshToken": {
            "type": "string",
            "description": "Token used to refresh the JWT token",
            "example": "rt_eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
          },
          "expiresIn": {
            "type": "integer",
            "format": "int32",
            "description": "Token expiration time in seconds",
            "example": 3600
          }
        }
      },
      "TokenRequest": {
        "type": "object",
        "required": [
          "refreshToken"
        ],
        "properties": {
          "refreshToken": {
            "type": "string",
            "description": "Refresh token received from login",
            "example": "rt_eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
          }
        }
      },
      "TokenResponse": {
        "type": "object",
        "required": [
          "token",
          "refreshToken",
          "expiresIn"
        ],
        "properties": {
          "token": {
            "type": "string",
            "description": "New JWT token",
            "example": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
          },
          "refreshToken": {
            "type": "string",
            "description": "New refresh token",
            "example": "rt_eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
          },
          "expiresIn": {
            "type": "integer",
            "format": "int32",
            "description": "Token expiration time in seconds",
            "example": 3600
          }
        }
      },
      "BaseErrorResponse": {
        "type": "object",
        "properties": {
          "error": {
            "type": "string",
            "description": "Error message"
          },
          "code": {
            "type": "string",
            "description": "Error code"
          }
        }
      },
      "Error400": {
        "allOf": [
          {
            "$ref": "#/components/schemas/BaseErrorResponse"
          }
        ],
        "example": {
          "error": "Bad Request - Invalid parameters or missing required fields",
          "code": 400
        }
      },
      "Error401": {
        "allOf": [
          {
            "$ref": "#/components/schemas/BaseErrorResponse"
          }
        ],
        "example": {
          "error": "Unauthorized - Invalid or missing authentication token",
          "code": 401
        }
      },
      "Error402": {
        "allOf": [
          {
            "$ref": "#/components/schemas/BaseErrorResponse"
          }
        ],
        "example": {
          "error": "Payment Required - Your subscription has expired or you have reached your quota",
          "code": 402
        }
      },
      "Error403": {
        "allOf": [
          {
            "$ref": "#/components/schemas/BaseErrorResponse"
          }
        ],
        "example": {
          "error": "Forbidden - You don't have permission to access this resource",
          "code": 403
        }
      },
      "Error413": {
        "allOf": [
          {
            "$ref": "#/components/schemas/BaseErrorResponse"
          }
        ],
        "example": {
          "error": "Payload Too Large - The file size exceeds the maximum allowed limit (2GB)",
          "code": 413
        }
      }
    }
  },
  "paths": {
    "/login": {
      "post": {
        "tags": [
          "Authentication"
        ],
        "summary": "Authenticate to the API",
        "description": "Authenticate to the API using your client credentials. Returns a token needed for all other routes.",
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/LoginRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successfully authenticated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LoginResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request - Invalid parameters",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error400"
                }
              }
            }
          },
          "401": {
            "description": "Invalid credentials",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error401"
                }
              }
            }
          }
        }
      }
    },
    "/token": {
      "post": {
        "tags": [
          "Authentication"
        ],
        "summary": "Refresh access token",
        "description": "Refresh an expired access token using the refresh token. The Bearer token can be expired.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TokenRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Token successfully refreshed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TokenResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request - Invalid parameters",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error400"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized - Invalid token",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error401"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden - Insufficient permissions",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error403"
                }
              }
            }
          }
        }
      }
    },
    "/innovation-service/anonymization": {
      "post": {
        "tags": [
          "Anonymization"
        ],
        "summary": "Start an anonymization job",
        "description": "This route will create a job for anonymizing faces and/or license plates in images or videos. The process is asynchronous and will return a job ID that can be used to check the status.\n\nNote: For a basic request, only the `input_media` field is required. All other form fields should be disabled in the test interface.",
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "required": [
                  "input_media"
                ],
                "properties": {
                  "input_media": {
                    "type": "string",
                    "format": "binary",
                    "description": "Image or video file to process. Accepted formats are JPEG, PNG, WEBP, MP4, AVI, MOV, MKV, ZIP."
                  },
                  "activation_faces_blur": {
                    "type": "boolean",
                    "description": "Enable face detection and blurring",
                    "example": true
                  },
                  "activation_plates_blur": {
                    "type": "boolean",
                    "description": "Enable license plate detection and blurring",
                    "example": true
                  },
                  "output_detections_url": {
                    "type": "boolean",
                    "description": "Return URLs to download detection coordinates in JSON format",
                    "example": true
                  },
                  "included_area": {
                    "type": "object",
                    "properties": {
                      "top": {
                        "type": "number",
                        "minimum": 0,
                        "maximum": 1
                      },
                      "bottom": {
                        "type": "number",
                        "minimum": 0,
                        "maximum": 1
                      },
                      "left": {
                        "type": "number",
                        "minimum": 0,
                        "maximum": 1
                      },
                      "right": {
                        "type": "number",
                        "minimum": 0,
                        "maximum": 1
                      }
                    },
                    "description": "Optional area to restrict detection (normalized coordinates)"
                  },
                  "blur_type": {
                    "type": "object",
                    "properties": {
                      "anonymization_type": {
                        "type": "string",
                        "enum": [
                          "blur",
                          "opaque",
                          "pixelate"
                        ],
                        "description": "Type of anonymization to apply"
                      },
                      "smooth_padding": {
                        "type": "number",
                        "description": "Blur intensity (only for **blur** type)",
                        "example": null,
                        "nullable": true
                      },
                      "hex_color": {
                        "type": "string",
                        "description": "Color in hexadecimal (only for **opaque** type)",
                        "example": null,
                        "nullable": true
                      },
                      "num_pixels": {
                        "type": "number",
                        "description": "Number of pixels (only for **pixelate** type)",
                        "example": null,
                        "nullable": true
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Job successfully created",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "anonymization_job_id": {
                      "type": "string",
                      "example": "client_uuid-SRV_ANONYMIZATION-abc123def456"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad Request - Invalid parameters",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error400"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized - Invalid token",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error401"
                }
              }
            }
          },
          "402": {
            "description": "Payment Required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error402"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden - Insufficient permissions",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error403"
                }
              }
            }
          },
          "413": {
            "description": "Payload Too Large",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error413"
                }
              }
            }
          }
        }
      },
      "get": {
        "tags": [
          "Anonymization"
        ],
        "summary": "Get anonymization job status",
        "description": "Check the status of an anonymization job.",
        "parameters": [
          {
            "name": "anonymization_job_id",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Job ID received from POST request",
              "example": "client_uuid-SRV_ANONYMIZATION-abc123def456"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Job status",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "string",
                      "enum": [
                        "Sent",
                        "Started",
                        "Succeeded",
                        "Failed"
                      ],
                      "description": "Current status of the job",
                      "example": "Succeeded"
                    },
                    "output_media": {
                      "type": "string",
                      "description": "URL to download the processed media (when status is completed)",
                      "example": "https://api.services.wassa.io/innovation-service/result/b83603c4-b9c7-4e86-9fe4-a2eeba2dfa06.jpeg"
                    },
                    "output_json": {
                      "type": "string",
                      "description": "URL to download the JSON with detection coordinates (when status is completed)",
                      "example": "https://api.services.wassa.io/innovation-service/result/b83603c4-b9c7-4e86-9fe4-a2eeba2dfa06.json"
                    },
                    "error": {
                      "type": "string",
                      "description": "Error message (when status is failed)",
                      "example": "Error message"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad Request - Invalid job ID",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error400"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized - Invalid token",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error401"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden - Insufficient permissions",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error403"
                }
              }
            }
          }
        }
      }
    },
    "/innovation-service/result/{fileName}": {
      "get": {
        "tags": [
          "Result"
        ],
        "summary": "Get result file",
        "description": "Download result file from BlurIt anonymization service.",
        "parameters": [
          {
            "name": "fileName",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "description": "File name received in output_media",
              "example": "b83603c4-b9c7-4e86-9fe4-a2eeba2dfa06.jpeg"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "File content",
            "content": {
              "application/octet-stream": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request - Invalid filename",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error400"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized - Invalid token",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error401"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden - Insufficient permissions",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error403"
                }
              }
            }
          }
        }
      }
    }
  }
}
