openapi: 3.0.3 info: title: Scampilot API description: | Complete REST API for Scampilot - AI-powered scam detection and prevention platform. ## Features - **AI Checks**: Submit text, links, images, or emails for scam analysis - **Questionnaires**: Interactive risk assessment questionnaires - **Usage Tracking**: Monitor API usage and limits - **Plan Management**: Access subscription plan information ## Authentication Most endpoints require Bearer token authentication using Laravel Sanctum. Create an API token from the Developer Portal at `/developer/tokens`. ## Rate Limiting - Authenticated users: 60 requests/minute - Anonymous users: 10 requests/minute - AI checks have additional usage limits based on subscription plan version: 1.1.0 contact: name: Scampilot API Support email: api@scampilot.de url: https://scampilot.de license: name: Proprietary url: https://scampilot.de/terms servers: - url: https://scampilot.de/api description: Production server - url: https://scampilot.test/api description: Development server tags: - name: Authentication description: User registration and authentication - name: User description: User information and authentication - name: AI Checks description: Scam detection and analysis - name: Inbound Emails description: Inbound email management and training data - name: Questionnaires description: Interactive risk assessment - name: Plans description: Subscription plan management - name: Usage description: Usage tracking and limits - name: Webhooks description: Webhook callbacks security: - BearerAuth: [] paths: /register: post: tags: - Authentication summary: Register new user description: Create a new user account security: [] requestBody: required: true content: application/json: schema: type: object required: - name - email - password - password_confirmation properties: name: type: string email: type: string format: email password: type: string format: password minLength: 8 password_confirmation: type: string format: password responses: '201': description: User created successfully content: application/json: schema: type: object properties: message: type: string user: $ref: '#/components/schemas/User' '422': $ref: '#/components/responses/ValidationError' /login: post: tags: - Authentication summary: Login user description: Authenticate user and receive OAuth2 access token with refresh token security: [] requestBody: required: true content: application/json: schema: type: object required: - email - password properties: email: type: string format: email password: type: string format: password scope: type: string description: Optional OAuth2 scope responses: '200': description: Login successful content: application/json: schema: type: object properties: token_type: type: string example: Bearer access_token: type: string refresh_token: type: string expires_in: type: integer user: $ref: '#/components/schemas/User' '422': $ref: '#/components/responses/ValidationError' /logout: post: tags: - Authentication summary: Logout user description: Revoke the current access token security: - BearerAuth: [] responses: '200': description: Logout successful content: application/json: schema: type: object properties: message: type: string '401': $ref: '#/components/responses/Unauthorized' /user: get: tags: - User summary: Get authenticated user description: Retrieve the currently authenticated user's information security: - BearerAuth: [] responses: '200': description: User information content: application/json: schema: $ref: '#/components/schemas/User' '401': $ref: '#/components/responses/Unauthorized' /plans: get: tags: - Plans summary: List all plans description: Get all active subscription plans security: [] responses: '200': description: List of plans content: application/json: schema: type: object properties: plans: type: array items: $ref: '#/components/schemas/Plan' /plans/compare: get: tags: - Plans summary: Compare plans description: Get a detailed comparison of all subscription plans security: [] responses: '200': description: Plan comparison content: application/json: schema: type: object properties: plans: type: array items: $ref: '#/components/schemas/PlanComparison' /plans/{name}: get: tags: - Plans summary: Get plan by name description: Get details of a specific plan security: [] parameters: - name: name in: path required: true schema: type: string enum: [free, pro, family] responses: '200': description: Plan details content: application/json: schema: $ref: '#/components/schemas/Plan' '404': $ref: '#/components/responses/NotFound' /plans/{name}/features: get: tags: - Plans summary: Get plan features description: Get detailed feature breakdown for a specific plan security: [] parameters: - name: name in: path required: true schema: type: string responses: '200': description: Plan features content: application/json: schema: $ref: '#/components/schemas/PlanFeatures' /plans/current: get: tags: - Plans summary: Get current user's plan description: Get the authenticated user's current subscription plan and usage statistics security: - BearerAuth: [] responses: '200': description: Current plan details content: application/json: schema: $ref: '#/components/schemas/CurrentPlan' '401': $ref: '#/components/responses/Unauthorized' /checks: post: tags: - AI Checks summary: Create AI check description: | Submit content for AI-powered scam analysis. Supports text, links, images, and emails. Analysis is performed asynchronously - use the status endpoint to poll for results. security: [] requestBody: required: true content: application/json: schema: oneOf: - $ref: '#/components/schemas/TextCheckRequest' - $ref: '#/components/schemas/LinkCheckRequest' examples: text: summary: Text check value: type: text content: "URGENT: Your bank account will be closed! Click here immediately..." link: summary: Link check value: type: link url: "https://suspicious-site.com/win-prize" content: "Received this link via SMS" multipart/form-data: schema: $ref: '#/components/schemas/ImageCheckRequest' responses: '201': description: Check created successfully content: application/json: schema: $ref: '#/components/schemas/CheckCreated' '422': $ref: '#/components/responses/ValidationError' '429': $ref: '#/components/responses/RateLimitExceeded' get: tags: - AI Checks summary: List user's checks description: Get history of all checks (Premium feature) security: - BearerAuth: [] parameters: - name: page in: query schema: type: integer default: 1 - name: per_page in: query schema: type: integer default: 20 maximum: 100 responses: '200': description: List of checks content: application/json: schema: $ref: '#/components/schemas/CheckList' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' /checks/{uuid}: get: tags: - AI Checks summary: Get check details description: Retrieve full details of a completed check security: [] parameters: - name: uuid in: path required: true schema: type: string format: uuid responses: '200': description: Check details content: application/json: schema: $ref: '#/components/schemas/Check' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' /checks/{uuid}/status: get: tags: - AI Checks summary: Get check status description: Check the current status of an AI analysis security: [] parameters: - name: uuid in: path required: true schema: type: string format: uuid responses: '200': description: Check status content: application/json: schema: $ref: '#/components/schemas/CheckStatus' '404': $ref: '#/components/responses/NotFound' /checks/{uuid}/export: get: tags: - AI Checks summary: Export check as PDF description: Export a check result as PDF (Premium feature) security: - BearerAuth: [] parameters: - name: uuid in: path required: true schema: type: string format: uuid responses: '200': description: PDF file content: application/pdf: schema: type: string format: binary '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' /usage: get: tags: - Usage summary: Get usage statistics description: Get current usage statistics for authenticated or anonymous user security: [] responses: '200': description: Usage statistics content: application/json: schema: $ref: '#/components/schemas/UsageStats' /usage/feature/{feature}: get: tags: - Usage summary: Get feature usage description: Get usage statistics for a specific feature security: - BearerAuth: [] parameters: - name: feature in: path required: true schema: type: string enum: [ai_check, pdf_export, questionnaire] - name: period in: query schema: type: string enum: [today, week, month, year, all] default: today responses: '200': description: Feature usage content: application/json: schema: $ref: '#/components/schemas/FeatureUsage' '401': $ref: '#/components/responses/Unauthorized' /usage/history: get: tags: - Usage summary: Get usage history description: Get detailed usage history security: - BearerAuth: [] parameters: - name: feature in: query schema: type: string - name: start_date in: query schema: type: string format: date - name: end_date in: query schema: type: string format: date - name: per_page in: query schema: type: integer minimum: 1 maximum: 100 default: 50 responses: '200': description: Usage history content: application/json: schema: $ref: '#/components/schemas/UsageHistory' '401': $ref: '#/components/responses/Unauthorized' /usage/breakdown: get: tags: - Usage summary: Get usage breakdown description: Get usage breakdown by feature security: - BearerAuth: [] parameters: - name: start_date in: query schema: type: string format: date - name: end_date in: query schema: type: string format: date responses: '200': description: Usage breakdown content: application/json: schema: $ref: '#/components/schemas/UsageBreakdown' '401': $ref: '#/components/responses/Unauthorized' /usage/can-perform/{feature}: get: tags: - Usage summary: Check if action can be performed description: Check if user can perform a specific action based on limits security: [] parameters: - name: feature in: path required: true schema: type: string responses: '200': description: Action permission check content: application/json: schema: $ref: '#/components/schemas/CanPerform' /questionnaires: get: tags: - Questionnaires summary: List all questionnaires description: Get all active questionnaires security: [] responses: '200': description: List of questionnaires content: application/json: schema: type: object properties: questionnaires: type: array items: $ref: '#/components/schemas/QuestionnaireSummary' /questionnaires/category/{category}: get: tags: - Questionnaires summary: Get questionnaires by category description: Filter questionnaires by category security: [] parameters: - name: category in: path required: true schema: type: string enum: [phishing, enkeltrick, fake-shop, general] responses: '200': description: Filtered questionnaires content: application/json: schema: type: object properties: questionnaires: type: array items: $ref: '#/components/schemas/QuestionnaireSummary' /questionnaires/{slug}: get: tags: - Questionnaires summary: Get questionnaire details description: Get a specific questionnaire with all questions and options security: [] parameters: - name: slug in: path required: true schema: type: string responses: '200': description: Questionnaire details content: application/json: schema: type: object properties: questionnaire: $ref: '#/components/schemas/Questionnaire' '404': $ref: '#/components/responses/NotFound' /questionnaires/{slug}/start: post: tags: - Questionnaires summary: Start questionnaire description: Begin a new questionnaire session security: [] parameters: - name: slug in: path required: true schema: type: string responses: '201': description: Questionnaire started content: application/json: schema: $ref: '#/components/schemas/QuestionnaireStarted' '404': $ref: '#/components/responses/NotFound' /questionnaire-responses/{uuid}/submit: post: tags: - Questionnaires summary: Submit questionnaire answers description: Submit all answers for a questionnaire and receive risk assessment security: [] parameters: - name: uuid in: path required: true schema: type: string format: uuid requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/QuestionnaireSubmission' responses: '200': description: Assessment completed content: application/json: schema: $ref: '#/components/schemas/QuestionnaireAssessment' '400': description: Bad request (e.g., already completed) '422': $ref: '#/components/responses/ValidationError' /questionnaire-responses/{uuid}: get: tags: - Questionnaires summary: Get questionnaire result description: Retrieve the results of a completed questionnaire security: [] parameters: - name: uuid in: path required: true schema: type: string format: uuid responses: '200': description: Questionnaire result content: application/json: schema: type: object properties: assessment: $ref: '#/components/schemas/Assessment' '400': description: Questionnaire not completed '404': $ref: '#/components/responses/NotFound' /webhooks/ai-check/{uuid}: post: tags: - Webhooks summary: AI check webhook callback description: Endpoint for n8n to send AI analysis results security: [] parameters: - name: uuid in: path required: true schema: type: string format: uuid requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/WebhookPayload' responses: '200': description: Webhook processed content: application/json: schema: type: object properties: message: type: string status: type: string '404': $ref: '#/components/responses/NotFound' /postmark/inbound: post: tags: - Webhooks summary: Postmark inbound webhook description: Endpoint for Postmark to send inbound emails (requires custom authentication) security: [] requestBody: required: true content: application/json: schema: type: object properties: MessageID: type: string From: type: string To: type: string Subject: type: string TextBody: type: string HtmlBody: type: string StrippedTextReply: type: string Attachments: type: array items: type: object responses: '200': description: Email received successfully content: application/json: schema: type: object properties: status: type: string message: type: string uuid: type: string format: uuid '400': description: Bad request '500': description: Server error /inbound-emails: get: tags: - Inbound Emails summary: List inbound emails description: Get list of inbound emails with filtering options (requires authentication) security: - BearerAuth: [] parameters: - name: status in: query schema: type: string enum: [pending, processing, processed, failed] - name: from in: query schema: type: string description: Filter by sender email - name: to in: query schema: type: string description: Filter by recipient email - name: from_date in: query schema: type: string format: date - name: to_date in: query schema: type: string format: date - name: per_page in: query schema: type: integer default: 15 maximum: 100 responses: '200': description: List of inbound emails content: application/json: schema: $ref: '#/components/schemas/InboundEmailList' '401': $ref: '#/components/responses/Unauthorized' /inbound-emails/statistics: get: tags: - Inbound Emails summary: Get inbound email statistics description: Get statistical overview of inbound emails (requires authentication) security: - BearerAuth: [] responses: '200': description: Statistics content: application/json: schema: type: object properties: data: type: object properties: total: type: integer pending: type: integer processing: type: integer processed: type: integer failed: type: integer training_data: type: integer with_ai_check: type: integer today: type: integer this_week: type: integer this_month: type: integer '401': $ref: '#/components/responses/Unauthorized' /inbound-emails/{uuid}: get: tags: - Inbound Emails summary: Get inbound email details description: Get detailed information about a specific inbound email (requires authentication) security: - BearerAuth: [] parameters: - name: uuid in: path required: true schema: type: string format: uuid responses: '200': description: Inbound email details content: application/json: schema: type: object properties: data: $ref: '#/components/schemas/InboundEmail' '401': $ref: '#/components/responses/Unauthorized' '404': $ref: '#/components/responses/NotFound' /training-data: get: tags: - Inbound Emails summary: Get training data emails description: Get inbound emails marked as training data (admin only) security: - BearerAuth: [] parameters: - name: ai_status in: query schema: type: string - name: risk_level in: query schema: type: string enum: [safe, warning, danger] - name: from_date in: query schema: type: string format: date - name: to_date in: query schema: type: string format: date - name: per_page in: query schema: type: integer default: 15 maximum: 100 responses: '200': description: Training data content: application/json: schema: $ref: '#/components/schemas/InboundEmailList' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' /training-data/export: get: tags: - Inbound Emails summary: Export training data description: Export training data in JSON format (admin only) security: - BearerAuth: [] parameters: - name: risk_level in: query schema: type: string enum: [safe, warning, danger] - name: limit in: query schema: type: integer responses: '200': description: Exported training data content: application/json: schema: type: object properties: exported_at: type: string format: date-time total_records: type: integer data: type: array items: $ref: '#/components/schemas/TrainingDataExport' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' components: securitySchemes: BearerAuth: type: http scheme: bearer bearerFormat: token description: Laravel Sanctum API token schemas: User: type: object properties: id: type: integer name: type: string email: type: string format: email email_verified_at: type: string format: date-time nullable: true profile_photo_url: type: string format: uri created_at: type: string format: date-time updated_at: type: string format: date-time Plan: type: object properties: id: type: integer name: type: string display_name: type: string description: type: string price_monthly: type: string price_yearly: type: string checks_per_day: type: integer nullable: true checks_per_month: type: integer nullable: true unlimited_checks: type: boolean features: type: array items: type: string is_active: type: boolean PlanComparison: type: object properties: name: type: string display_name: type: string description: type: string price_monthly: type: string price_yearly: type: string features: type: array items: type: string limits: type: object properties: checks_per_day: type: integer nullable: true checks_per_month: type: integer nullable: true unlimited_checks: type: boolean access: type: object properties: premium_courses: type: boolean pdf_export: type: boolean history: type: boolean priority_support: type: boolean max_family_members: type: integer nullable: true PlanFeatures: type: object properties: plan: type: string display_name: type: string features: type: array items: type: string capabilities: type: object properties: unlimited_checks: type: boolean premium_courses: type: boolean pdf_export: type: boolean history_access: type: boolean daily_limit: type: integer nullable: true monthly_limit: type: integer nullable: true CurrentPlan: type: object properties: plan: $ref: '#/components/schemas/Plan' is_authenticated: type: boolean usage: type: object properties: today: type: integer this_month: type: integer all_time: type: integer remaining: type: integer nullable: true subscription: type: object properties: is_subscribed: type: boolean on_trial: type: boolean ends_at: type: string format: date-time nullable: true TextCheckRequest: type: object required: - type - content properties: type: type: string enum: [text, email] content: type: string locale: type: string enum: [de, en] default: de LinkCheckRequest: type: object required: - type - url properties: type: type: string enum: [link] url: type: string format: uri content: type: string description: Optional context about the link locale: type: string enum: [de, en] default: de ImageCheckRequest: type: object required: - type - image properties: type: type: string enum: [image] image: type: string format: binary description: Image file (max 10MB) content: type: string description: Optional description locale: type: string enum: [de, en] default: de CheckCreated: type: object properties: message: type: string check: type: object properties: uuid: type: string format: uuid type: type: string risk_level: type: string nullable: true webhook_status: type: string created_at: type: string format: date-time status: type: string Check: type: object properties: uuid: type: string format: uuid type: type: string enum: [text, image, link, email] content: type: string nullable: true url: type: string nullable: true risk_level: type: string enum: [safe, warning, danger] nullable: true risk_score: type: integer minimum: 0 maximum: 100 nullable: true ai_explanation: type: string nullable: true ai_indicators: type: array items: type: string nullable: true risk_text: type: string nullable: true risk_color: type: string nullable: true webhook_status: type: string created_at: type: string format: date-time webhook_completed_at: type: string format: date-time nullable: true CheckStatus: type: object properties: uuid: type: string format: uuid status: type: string risk_level: type: string nullable: true is_complete: type: boolean is_pending: type: boolean has_failed: type: boolean CheckList: type: object properties: data: type: array items: $ref: '#/components/schemas/Check' links: type: object meta: type: object properties: current_page: type: integer from: type: integer last_page: type: integer per_page: type: integer to: type: integer total: type: integer UsageStats: type: object properties: usage: type: object properties: today: type: integer this_month: type: integer all_time: type: integer remaining: type: integer nullable: true limit: type: integer nullable: true is_unlimited: type: boolean plan: type: object properties: name: type: string display_name: type: string FeatureUsage: type: object properties: feature: type: string period: type: string usage: type: integer UsageHistory: type: object properties: data: type: array items: type: object properties: id: type: integer feature: type: string resource_type: type: string quantity: type: integer used_at: type: string format: date-time links: type: object meta: type: object UsageBreakdown: type: object properties: breakdown: type: array items: type: object properties: feature: type: string count: type: integer total_quantity: type: integer total_records: type: integer total_quantity: type: integer CanPerform: type: object properties: can_perform: type: boolean remaining: type: integer nullable: true limit: type: integer nullable: true is_unlimited: type: boolean QuestionnaireSummary: type: object properties: slug: type: string title: type: string description: type: string category: type: string category_name: type: string icon: type: string estimated_duration: type: integer Questionnaire: type: object properties: slug: type: string title: type: string description: type: string category: type: string estimated_duration: type: integer questions: type: array items: $ref: '#/components/schemas/Question' Question: type: object properties: id: type: integer type: type: string enum: [yes_no, single_choice, multiple_choice, text, scale] question_text: type: string help_text: type: string nullable: true is_required: type: boolean order: type: integer options: type: array items: $ref: '#/components/schemas/QuestionOption' QuestionOption: type: object properties: id: type: integer option_text: type: string order: type: integer QuestionnaireStarted: type: object properties: message: type: string response: type: object properties: uuid: type: string format: uuid questionnaire: type: object properties: slug: type: string title: type: string started_at: type: string format: date-time QuestionnaireSubmission: type: object required: - answers properties: answers: type: array items: oneOf: - type: object properties: question_id: type: integer option_id: type: integer - type: object properties: question_id: type: integer option_ids: type: array items: type: integer - type: object properties: question_id: type: integer text: type: string QuestionnaireAssessment: type: object properties: message: type: string assessment: $ref: '#/components/schemas/Assessment' Assessment: type: object properties: uuid: type: string format: uuid questionnaire: type: object properties: title: type: string category: type: string risk_score: type: integer minimum: 0 maximum: 100 risk_level: type: string enum: [low, medium, high, critical] risk_text: type: string risk_color: type: string risk_icon: type: string assessment_summary: type: string recommended_actions: type: array items: type: string help_contacts: type: array items: type: object properties: name: type: string phone: type: string description: type: string urgent: type: boolean completion_time: type: integer description: Time to complete in minutes completed_at: type: string format: date-time WebhookPayload: type: object required: - risk_level - risk_score - explanation properties: risk_level: type: string enum: [safe, warning, danger] risk_score: type: integer minimum: 0 maximum: 100 explanation: type: string indicators: type: array items: type: string InboundEmail: type: object properties: uuid: type: string format: uuid from: type: object properties: email: type: string name: type: string nullable: true to: type: object properties: email: type: string name: type: string nullable: true subject: type: string text_body: type: string nullable: true html_body: type: string nullable: true stripped_text_reply: type: string nullable: true attachments: type: array nullable: true attachment_count: type: integer status: type: string enum: [pending, processing, processed, failed] is_training_data: type: boolean ai_check_uuid: type: string format: uuid nullable: true received_at: type: string format: date-time processed_at: type: string format: date-time nullable: true created_at: type: string format: date-time InboundEmailList: type: object properties: data: type: array items: $ref: '#/components/schemas/InboundEmail' links: type: object meta: type: object properties: current_page: type: integer from: type: integer last_page: type: integer per_page: type: integer to: type: integer total: type: integer TrainingDataExport: type: object properties: id: type: integer uuid: type: string format: uuid received_at: type: string format: date-time from_email: type: string subject: type: string content: type: string has_attachments: type: boolean attachment_count: type: integer ai_analysis: type: object nullable: true properties: uuid: type: string format: uuid risk_level: type: string risk_score: type: integer explanation: type: string indicators: type: array items: type: string status: type: string analyzed_at: type: string format: date-time Error: type: object properties: message: type: string error: type: string errors: type: object additionalProperties: type: array items: type: string responses: Unauthorized: description: Unauthorized - Invalid or missing authentication token content: application/json: schema: $ref: '#/components/schemas/Error' example: message: "Unauthenticated." Forbidden: description: Forbidden - Insufficient permissions content: application/json: schema: $ref: '#/components/schemas/Error' example: error: "Upgrade erforderlich" message: "Diese Funktion ist nur für Pro-Nutzer verfügbar" upgrade_url: "https://scampilot.de/billing" NotFound: description: Not Found - Resource does not exist content: application/json: schema: $ref: '#/components/schemas/Error' example: message: "No query results for model." ValidationError: description: Validation Error - Invalid request data content: application/json: schema: $ref: '#/components/schemas/Error' example: message: "The given data was invalid." errors: content: - "Bitte geben Sie den zu prüfenden Inhalt ein." RateLimitExceeded: description: Rate Limit Exceeded content: application/json: schema: $ref: '#/components/schemas/Error' example: error: "Limit erreicht" message: "Sie haben Ihr tägliches Limit erreicht" remaining: 0 limit: 5 upgrade_url: "https://scampilot.de/billing"