{
  "openapi": "3.0.3",
  "info": {
    "title": "Shakebug API",
    "version": "1.0.0",
    "description": "Public v1.0 API for the Shakebug bug & crash reporting platform. Authenticate with OAuth 2.0 (authorization code) and pass the resulting Bearer access token. All list/read endpoints are scoped to projects you own and to your plan's data-retention window.",
    "contact": { "name": "Shakebug Support", "email": "support@shakebug.com", "url": "https://shakebug.com" }
  },
  "servers": [
    { "url": "https://app.shakebug.com", "description": "Production" }
  ],
  "security": [ { "oauth2": [] }, { "bearerAuth": [] } ],
  "tags": [
    { "name": "Auth" },
    { "name": "Projects" },
    { "name": "Bugs" },
    { "name": "Crashes" },
    { "name": "Analytics" },
    { "name": "Webhooks" }
  ],
  "paths": {
    "/v1.0/authorize/token": {
      "post": {
        "tags": ["Auth"],
        "summary": "Exchange an authorization code (or refresh token) for an access token",
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "type": "object",
                "properties": {
                  "grant_type": { "type": "string", "enum": ["authorization_code", "refresh_token"] },
                  "code": { "type": "string" },
                  "refresh_token": { "type": "string" },
                  "redirect_uri": { "type": "string" },
                  "client_id": { "type": "string" },
                  "client_secret": { "type": "string" }
                },
                "required": ["grant_type", "client_id", "client_secret"]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Token issued",
            "content": { "application/json": { "schema": {
              "type": "object",
              "properties": {
                "access_token": { "type": "string" },
                "token_type": { "type": "string", "example": "Bearer" },
                "expires_in": { "type": "integer", "example": 3600 },
                "refresh_token": { "type": "string" },
                "scope": { "type": "string" }
              }
            } } }
          },
          "400": { "$ref": "#/components/responses/Error" },
          "401": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/v1.0/authorize/me": {
      "get": {
        "tags": ["Auth"],
        "summary": "Identity behind the access token",
        "responses": {
          "200": {
            "description": "Authenticated identity",
            "content": { "application/json": { "schema": {
              "type": "object",
              "properties": {
                "status": { "type": "integer", "example": 200 },
                "data": {
                  "type": "object",
                  "properties": {
                    "user_id": { "type": "string" },
                    "name": { "type": "string" },
                    "email": { "type": "string" }
                  }
                }
              }
            } } }
          },
          "401": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/v1.0/projects": {
      "get": {
        "tags": ["Projects"],
        "summary": "List projects",
        "responses": {
          "200": {
            "description": "Projects",
            "content": { "application/json": { "schema": {
              "type": "object",
              "properties": {
                "status": { "type": "integer", "example": 200 },
                "data": {
                  "type": "object",
                  "properties": {
                    "projects": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": { "type": "string" },
                          "name": { "type": "string" },
                          "platform": { "type": "string" }
                        }
                      }
                    }
                  }
                }
              }
            } } }
          },
          "401": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/v1.0/bug": {
      "post": {
        "tags": ["Bugs"],
        "summary": "Create a bug or crash",
        "requestBody": {
          "required": true,
          "content": { "application/json": { "schema": {
            "type": "object",
            "required": ["project", "description"],
            "properties": {
              "project": { "type": "string", "description": "Project id from /v1.0/projects" },
              "description": { "type": "string" },
              "bugtypes": { "type": "string", "enum": ["bug", "crashed"], "default": "bug" },
              "email": { "type": "string" },
              "devicemodel": { "type": "string" },
              "osversion": { "type": "string" },
              "memory": { "type": "string" },
              "batteryLevel": { "type": "string" },
              "internettype": { "type": "string" }
            }
          } } }
        },
        "responses": {
          "200": {
            "description": "Created",
            "content": { "application/json": { "schema": {
              "type": "object",
              "properties": {
                "status": { "type": "integer", "example": 200 },
                "data": { "type": "object", "properties": { "bug_id": { "type": "string" } } }
              }
            } } }
          },
          "400": { "$ref": "#/components/responses/Error" },
          "401": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/v1.0/bug/attachment": {
      "post": {
        "tags": ["Bugs"],
        "summary": "Attach an image or video to a bug",
        "requestBody": {
          "required": true,
          "content": { "multipart/form-data": { "schema": {
            "type": "object",
            "required": ["bug_id", "attachment"],
            "properties": {
              "bug_id": { "type": "string" },
              "attachment": { "type": "string", "format": "binary" }
            }
          } } }
        },
        "responses": {
          "200": { "description": "Attached" },
          "400": { "$ref": "#/components/responses/Error" },
          "401": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/v1.0/bug/getbug": {
      "get": {
        "tags": ["Bugs"],
        "summary": "List bugs and/or crashes (with filters)",
        "description": "The single list endpoint. Omit type to return both bugs and crashes.",
        "parameters": [
          { "$ref": "#/components/parameters/applicationId" },
          { "name": "type", "in": "query", "schema": { "type": "string", "enum": ["bug", "crashed"] } },
          { "name": "status", "in": "query", "schema": { "type": "integer", "enum": [0, 1, 2, 3, 4] } },
          { "name": "appversion", "in": "query", "schema": { "type": "string" } },
          { "name": "devicemodel", "in": "query", "schema": { "type": "string" } },
          { "name": "from", "in": "query", "schema": { "type": "string", "format": "date" } },
          { "name": "to", "in": "query", "schema": { "type": "string", "format": "date" } },
          { "$ref": "#/components/parameters/page" },
          { "$ref": "#/components/parameters/limit" }
        ],
        "responses": {
          "200": {
            "description": "Paged bug list",
            "content": { "application/json": { "schema": {
              "type": "object",
              "properties": {
                "status": { "type": "boolean", "example": true },
                "data": {
                  "type": "object",
                  "properties": {
                    "pagination": { "$ref": "#/components/schemas/Pagination" },
                    "filters": { "type": "object" },
                    "count": { "type": "integer" },
                    "records": { "type": "array", "items": { "$ref": "#/components/schemas/BugRecord" } }
                  }
                }
              }
            } } }
          },
          "401": { "$ref": "#/components/responses/Error" },
          "403": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/v1.0/bug/getcrash": {
      "get": {
        "tags": ["Crashes"],
        "summary": "List crashes (shortcut for getbug with type=crashed)",
        "parameters": [
          { "$ref": "#/components/parameters/applicationId" },
          { "$ref": "#/components/parameters/page" },
          { "$ref": "#/components/parameters/limit" }
        ],
        "responses": {
          "200": { "description": "Paged crash list" },
          "401": { "$ref": "#/components/responses/Error" },
          "403": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/v1.0/bug/detail": {
      "get": {
        "tags": ["Bugs"],
        "summary": "Full detail for a single bug or crash",
        "parameters": [
          { "name": "bug_id", "in": "query", "required": true, "schema": { "type": "string" }, "description": "Encrypted bug id from a list endpoint" }
        ],
        "responses": {
          "200": {
            "description": "Bug detail",
            "content": { "application/json": { "schema": {
              "type": "object",
              "properties": {
                "status": { "type": "boolean", "example": true },
                "data": { "$ref": "#/components/schemas/BugDetail" }
              }
            } } }
          },
          "400": { "$ref": "#/components/responses/Error" },
          "401": { "$ref": "#/components/responses/Error" },
          "404": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/v1.0/crashes/groups": {
      "get": {
        "tags": ["Crashes"],
        "summary": "Crashes grouped by signature, most frequent first",
        "parameters": [
          { "$ref": "#/components/parameters/applicationId" },
          { "name": "from", "in": "query", "schema": { "type": "string", "format": "date" } },
          { "name": "to", "in": "query", "schema": { "type": "string", "format": "date" } },
          { "$ref": "#/components/parameters/page" },
          { "$ref": "#/components/parameters/limit" }
        ],
        "responses": {
          "200": {
            "description": "Crash groups",
            "content": { "application/json": { "schema": {
              "type": "object",
              "properties": {
                "status": { "type": "boolean", "example": true },
                "data": {
                  "type": "object",
                  "properties": {
                    "pagination": { "$ref": "#/components/schemas/Pagination" },
                    "count": { "type": "integer" },
                    "groups": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "signature": { "type": "string" },
                          "occurrences": { "type": "integer" },
                          "affected_versions": { "type": "integer" },
                          "first_seen": { "type": "string" },
                          "last_seen": { "type": "string" },
                          "sample_bug_id": { "type": "string" }
                        }
                      }
                    }
                  }
                }
              }
            } } }
          },
          "401": { "$ref": "#/components/responses/Error" },
          "403": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/v1.0/analytics/summary": {
      "get": {
        "tags": ["Analytics"],
        "summary": "KPI rollup for a project",
        "parameters": [
          { "$ref": "#/components/parameters/applicationId" },
          { "name": "from", "in": "query", "schema": { "type": "string", "format": "date" } },
          { "name": "to", "in": "query", "schema": { "type": "string", "format": "date" } }
        ],
        "responses": {
          "200": { "description": "Analytics summary" },
          "401": { "$ref": "#/components/responses/Error" },
          "403": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/v1.0/webhook/subscribe": {
      "post": {
        "tags": ["Webhooks"],
        "summary": "Subscribe a URL to bug_created events",
        "requestBody": {
          "required": true,
          "content": { "application/json": { "schema": {
            "type": "object",
            "required": ["hookUrl"],
            "properties": {
              "hookUrl": { "type": "string", "description": "Target URL. Aliases: targetUrl, url." }
            }
          } } }
        },
        "responses": {
          "200": {
            "description": "Subscribed",
            "content": { "application/json": { "schema": {
              "type": "object",
              "properties": {
                "status": { "type": "integer", "example": 200 },
                "id": { "type": "integer" },
                "message": { "type": "string" }
              }
            } } }
          },
          "400": { "$ref": "#/components/responses/Error" },
          "401": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/v1.0/webhook/unsubscribe": {
      "post": {
        "tags": ["Webhooks"],
        "summary": "Remove a webhook subscription by id or hookUrl",
        "requestBody": {
          "required": true,
          "content": { "application/json": { "schema": {
            "type": "object",
            "properties": {
              "id": { "type": "integer" },
              "hookUrl": { "type": "string" }
            }
          } } }
        },
        "responses": {
          "200": { "description": "Unsubscribed" },
          "400": { "$ref": "#/components/responses/Error" },
          "401": { "$ref": "#/components/responses/Error" }
        }
      }
    },
    "/v1.0/webhook/sample_bugs": {
      "get": {
        "tags": ["Webhooks"],
        "summary": "Sample event payload (for automation field mapping)",
        "security": [],
        "responses": {
          "200": {
            "description": "Sample bug_created events",
            "content": { "application/json": { "schema": {
              "type": "array",
              "items": { "$ref": "#/components/schemas/WebhookEvent" }
            } } }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "oauth2": {
        "type": "oauth2",
        "flows": {
          "authorizationCode": {
            "authorizationUrl": "https://app.shakebug.com/v1.0/authorize",
            "tokenUrl": "https://app.shakebug.com/v1.0/authorize/token",
            "refreshUrl": "https://app.shakebug.com/v1.0/authorize/token",
            "scopes": { "read": "Read data", "write": "Create data" }
          }
        }
      },
      "bearerAuth": { "type": "http", "scheme": "bearer" }
    },
    "parameters": {
      "applicationId": {
        "name": "application_id", "in": "query", "required": true,
        "schema": { "type": "string" },
        "description": "Project id returned by GET /v1.0/projects"
      },
      "page": { "name": "page", "in": "query", "schema": { "type": "integer", "default": 1, "minimum": 1 } },
      "limit": { "name": "limit", "in": "query", "schema": { "type": "integer", "default": 20, "minimum": 1, "maximum": 100 } }
    },
    "schemas": {
      "Pagination": {
        "type": "object",
        "properties": {
          "total": { "type": "integer" },
          "page": { "type": "integer" },
          "limit": { "type": "integer" },
          "total_pages": { "type": "integer" }
        }
      },
      "BugRecord": {
        "type": "object",
        "properties": {
          "id": { "type": "string" },
          "description": { "type": "string" },
          "bugtypes": { "type": "string", "enum": ["bug", "crashed"] },
          "status": { "type": "string", "enum": ["To-Do", "Completed", "In Progress", "Testing", "Backlog"] },
          "platform": { "type": "string", "enum": ["Web", "Mobile"] },
          "devicemodel": { "type": "string", "nullable": true },
          "osversion": { "type": "string", "nullable": true },
          "memory": { "type": "string", "nullable": true },
          "batteryLevel": { "type": "string", "nullable": true },
          "internettype": { "type": "string", "nullable": true },
          "appversion": { "type": "string", "nullable": true },
          "attachment": { "type": "string", "nullable": true },
          "created": { "type": "string" }
        }
      },
      "BugDetail": {
        "allOf": [
          { "$ref": "#/components/schemas/BugRecord" },
          {
            "type": "object",
            "properties": {
              "project": { "type": "string" },
              "project_name": { "type": "string" },
              "email": { "type": "string", "nullable": true },
              "browser": {
                "type": "object",
                "nullable": true,
                "properties": {
                  "name": { "type": "string" },
                  "full_version": { "type": "string" },
                  "user_agent": { "type": "string" },
                  "language": { "type": "string" },
                  "platform": { "type": "string" },
                  "width": { "type": "string" },
                  "height": { "type": "string" }
                }
              }
            }
          }
        ]
      },
      "WebhookEvent": {
        "type": "object",
        "properties": {
          "event": { "type": "string", "example": "bug_created" },
          "data": {
            "type": "object",
            "properties": {
              "bug_id": { "type": "string" },
              "project": { "type": "string" },
              "bugtypes": { "type": "string" },
              "description": { "type": "string" },
              "platform": { "type": "string" },
              "device": { "type": "string" },
              "timestamp": { "type": "string" }
            }
          }
        }
      }
    },
    "responses": {
      "Error": {
        "description": "Error",
        "content": { "application/json": { "schema": {
          "type": "object",
          "properties": {
            "status": { "oneOf": [ { "type": "integer" }, { "type": "boolean" } ] },
            "error": { "type": "string" },
            "message": { "type": "string" }
          }
        } } }
      }
    }
  }
}
