{"openapi":"3.0.0","info":{"title":"Agently API","version":"v1.0.0","description":"Danmarks første Agentic AI Email Agent platform API. Administrer AI agents, konversationer og email automation.","contact":{"name":"Agently Support","email":"support@agently.dk","url":"https://agently.dk"},"license":{"name":"Proprietary","url":"https://agently.dk/terms"}},"servers":[{"url":"https://agently.dk/api/v1","description":"Production Server"},{"url":"http://localhost:3000/api/v1","description":"Current Environment"},{"url":"http://localhost:3000/api/v1","description":"Local Development"}],"paths":{"/health":{"get":{"summary":"System health check","description":"Kontroller systemets sundhed og tilgængelighed","tags":["System"],"security":[],"responses":{"200":{"description":"System is healthy","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HealthResponse"}}}},"503":{"description":"System is degraded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HealthResponse"}}}}}}},"/agents":{"get":{"summary":"List AI agents","description":"Hent alle aktive AI agents for authenticated user","tags":["Agents"],"security":[{"ApiKeyAuth":[]}],"responses":{"200":{"description":"List of AI agents","headers":{"X-Total-Count":{"description":"Antal agents returneret","schema":{"type":"integer"}},"X-RateLimit-Limit":{"description":"Rate limit grænse","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Resterende requests","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentsResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}},"post":{"summary":"Create AI agent","description":"Opret en ny AI agent med specifikke instruktioner og rolle","tags":["Agents"],"security":[{"ApiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateAgentRequest"}}}},"responses":{"201":{"description":"AI agent created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/agents/{id}":{"get":{"summary":"Get specific AI agent","description":"Hent detaljer om en specifik AI agent","tags":["Agent Management"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"Agent UUID"}],"responses":{"200":{"description":"Agent details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}},"put":{"summary":"Update AI agent","description":"Opdater AI agent konfiguration og indstillinger","tags":["Agent Management"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"Agent UUID"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateAgentRequest"}}}},"responses":{"200":{"description":"Agent opdateret succesfuldt","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}},"delete":{"summary":"Delete AI agent","description":"Slet AI agent permanent (kan ikke fortrydes)","tags":["Agent Management"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"Agent UUID"}],"responses":{"204":{"description":"Agent slettet succesfuldt"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/agents/{id}/availability":{"get":{"summary":"Get agent availability","description":"Hent agent tilgængeligheden (åbningstider og tidsslots)","tags":["Agent Management","Availability"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"Agent UUID"}],"responses":{"200":{"description":"Agent availability schedule","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AvailabilityResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}},"post":{"summary":"Update agent availability","description":"Opdater agent tilgængelighed med nye tidsslots","tags":["Agent Management","Availability"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"Agent UUID"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateAvailabilityRequest"}}}},"responses":{"200":{"description":"Tilgængelighed opdateret","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AvailabilityResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/agents/{id}/metrics":{"get":{"summary":"Get agent performance metrics","description":"Hent performance statistikker for AI agent (response time, satisfaction, conversation counts)","tags":["Agent Management","Analytics"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"Agent UUID"},{"name":"period","in":"query","schema":{"type":"string","enum":["24h","7d","30d","custom"],"default":"7d"},"description":"Tidsperiode for metrics"},{"name":"startDate","in":"query","schema":{"type":"string","format":"date"},"description":"Start dato (kun ved period=custom)"},{"name":"endDate","in":"query","schema":{"type":"string","format":"date"},"description":"Slut dato (kun ved period=custom)"}],"responses":{"200":{"description":"Agent performance metrics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentMetricsResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/agents/{id}/auto-booking":{"get":{"summary":"Get auto-booking statistics","description":"Hent auto-booking performance og log data for agent","tags":["Agent Management","Auto-Booking"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"Agent UUID"},{"name":"stats","in":"query","schema":{"type":"boolean","default":true},"description":"Inkluder statistikker"},{"name":"start_date","in":"query","schema":{"type":"string","format":"date"},"description":"Start dato for statistikker"},{"name":"end_date","in":"query","schema":{"type":"string","format":"date"},"description":"Slut dato for statistikker"}],"responses":{"200":{"description":"Auto-booking statistics og logs","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AutoBookingStatsResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}},"post":{"summary":"Process auto-booking request","description":"Send email til agent for AI-powered booking analysis og automatisk booking","tags":["Agent Management","Auto-Booking"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"Agent UUID"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AutoBookingRequest"}}}},"responses":{"200":{"description":"Auto-booking analysis færdig","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AutoBookingResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/agents/{id}/rules":{"get":{"summary":"Get agent booking rules","description":"Hent business regler for agent booking (minimum notice, maksimum advance booking, møde typer, etc.)","tags":["Agent Management","Business Rules"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"Agent UUID"},{"name":"rule_type","in":"query","schema":{"type":"string","enum":["minimum_notice","maximum_advance","meeting_types","time_restrictions","customer_limits","buffer_override","approval_required"]},"description":"Filter på specifik regel type"},{"name":"active","in":"query","schema":{"type":"boolean"},"description":"Filter kun aktive regler"}],"responses":{"200":{"description":"Agent booking rules","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BookingRulesResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}},"post":{"summary":"Create booking rule","description":"Opret ny business regel for agent booking","tags":["Agent Management","Business Rules"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"Agent UUID"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateBookingRuleRequest"}}}},"responses":{"201":{"description":"Booking regel oprettet","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BookingRuleResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"Regel type eksisterer allerede","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/agents/{id}/knowledge/upload":{"get":{"summary":"Get agent knowledge base","description":"Hent agent vidensbase med automatisk sync af struktureret data","tags":["Agent Management","Knowledge Management"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"Agent UUID"}],"responses":{"200":{"description":"Agent knowledge base","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KnowledgeBaseResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}},"post":{"summary":"Upload knowledge items","description":"Upload bulk knowledge items til agent vidensbase med AI embeddings","tags":["Agent Management","Knowledge Management"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"Agent UUID"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UploadKnowledgeRequest"}}}},"responses":{"200":{"description":"Knowledge items uploadet succesfuldt","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KnowledgeUploadResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}},"delete":{"summary":"Delete knowledge items","description":"Slet knowledge items fra agent vidensbase (bulk operation)","tags":["Agent Management","Knowledge Management"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"Agent UUID"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"knowledgeIds":{"type":"array","items":{"type":"string","format":"uuid"},"description":"Liste af knowledge item IDs at slette"}}}}}},"responses":{"200":{"description":"Knowledge items slettet","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeleteKnowledgeResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/agents/{id}/structured-data":{"get":{"summary":"Get structured business data","description":"Hent agent strukturerede forretningsdata (virksomhedsinfo, services, priser, kommunikationsstil)","tags":["Agent Management","Business Context"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"Agent UUID"}],"responses":{"200":{"description":"Structured business data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StructuredDataResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}},"patch":{"summary":"Update structured business data","description":"Opdater agent strukturerede forretningsdata med automatisk knowledge base sync","tags":["Agent Management","Business Context"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"Agent UUID"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateStructuredDataRequest"}}}},"responses":{"200":{"description":"Strukturerede data opdateret","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StructuredDataResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/email-filters":{"get":{"summary":"List email filters","description":"Hent alle aktive email filters for bruger med mulighed for filtreringer","tags":["Email Filters"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"category","in":"query","schema":{"type":"string","enum":["spam","phishing","marketing","custom"]},"description":"Filtrer efter filter kategori"},{"name":"is_active","in":"query","schema":{"type":"boolean","default":true},"description":"Kun aktive filters"}],"responses":{"200":{"description":"Liste af email filters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailFiltersResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}},"post":{"summary":"Create email filter","description":"Opret ny email filter med konfigurerede regler og kriterier","tags":["Email Filters"],"security":[{"ApiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateEmailFilterRequest"}}}},"responses":{"201":{"description":"Email filter oprettet","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailFilterResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/email-filters/{id}":{"get":{"summary":"Get email filter details","description":"Hent detaljer for specifik email filter inkl. historik og performance","tags":["Email Filters"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"Email filter UUID"}],"responses":{"200":{"description":"Email filter detaljer","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailFilterResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}},"put":{"summary":"Update email filter","description":"Opdater email filter konfiguration og regler","tags":["Email Filters"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"Email filter UUID"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateEmailFilterRequest"}}}},"responses":{"200":{"description":"Email filter opdateret","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailFilterResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}},"delete":{"summary":"Deactivate email filter","description":"Deaktiver email filter (soft delete - bevarer historik)","tags":["Email Filters"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"Email filter UUID"}],"responses":{"200":{"description":"Email filter deaktiveret","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/email-filters/test":{"post":{"summary":"Test email filter","description":"Test hvordan et email ville blive behandlet af filter systemet","tags":["Email Filters","Testing"],"security":[{"ApiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TestEmailFilterRequest"}}}},"responses":{"200":{"description":"Filter test resultat","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailFilterTestResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/email-filters/stats":{"get":{"summary":"Get email filter statistics","description":"Hent performance statistikker for email filters med accuracy og usage metrics","tags":["Email Filters","Analytics"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"days","in":"query","schema":{"type":"integer","default":7,"minimum":1,"maximum":90},"description":"Antal dage at inkludere i statistikker"}],"responses":{"200":{"description":"Email filter statistikker","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailFilterStatsResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/email-filters/auto-learn":{"get":{"summary":"Get learning insights","description":"Hent indsigter fra auto-learning system for filter forbedringer","tags":["Email Filters","Machine Learning"],"security":[{"ApiKeyAuth":[]}],"responses":{"200":{"description":"Auto-learning indsigter","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AutoLearningInsightsResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}},"post":{"summary":"Trigger auto-learning","description":"Start auto-learning process for at analysere feedback og oprette nye filter mønstre","tags":["Email Filters","Machine Learning"],"security":[{"ApiKeyAuth":[]}],"responses":{"200":{"description":"Auto-learning proces komplet","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AutoLearningResultResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/email-filters/pending":{"get":{"summary":"Get pending email approvals","description":"Hent emails der afventer manuel godkendelse eller review","tags":["Email Filters","Manual Review"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"limit","in":"query","schema":{"type":"integer","default":50,"maximum":200},"description":"Maksimalt antal pending emails at returnere"}],"responses":{"200":{"description":"Pending email approvals","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PendingEmailsResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/email-filters/feedback":{"post":{"summary":"Provide filter feedback","description":"Giv feedback på filter beslutning for at forbedre accuracy og auto-learning","tags":["Email Filters","Machine Learning"],"security":[{"ApiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FilterFeedbackRequest"}}}},"responses":{"200":{"description":"Feedback registreret","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/email-filters/stop-asking":{"post":{"summary":"Stop feedback prompts","description":"Deaktiver feedback prompts for specifikke email typer eller generelt","tags":["Email Filters","User Preferences"],"security":[{"ApiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StopAskingRequest"}}}},"responses":{"200":{"description":"Feedback prompts stoppet","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/email-filters/cleanup-duplicates":{"post":{"summary":"Clean up duplicate filters","description":"Fjern duplikerede eller redundante email filters for optimal performance","tags":["Email Filters","Maintenance"],"security":[{"ApiKeyAuth":[]}],"responses":{"200":{"description":"Duplicate cleanup komplet","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CleanupResultResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/email-filters/unblock":{"post":{"summary":"Unblock email sender","description":"Fjern email adresse fra blokerings liste og tillad fremtidige emails","tags":["Email Filters","Unblock Management"],"security":[{"ApiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UnblockEmailRequest"}}}},"responses":{"200":{"description":"Email adresse unblocked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/conversations/toggle-mode":{"post":{"summary":"Toggle conversation mode","description":"Skift mellem AI automatisk og manuel håndtering for en specifik samtale","tags":["Conversations","AI Management"],"security":[{"SessionAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ToggleConversationModeRequest"}}}},"responses":{"200":{"description":"Samtale tilstand ændret succesfuldt","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/agents/{id}/conversations":{"get":{"summary":"Get agent conversations","description":"Hent alle samtaler for en specifik AI agent med filtering og paginering","tags":["Agents","Conversations"],"security":[{"SessionAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"description":"AI agent ID","schema":{"type":"string","format":"uuid"}},{"name":"status","in":"query","required":false,"description":"Filter samtaler efter status","schema":{"type":"string","enum":["active","resolved","escalated"]}},{"name":"limit","in":"query","required":false,"description":"Antal samtaler per side (max 100)","schema":{"type":"integer","minimum":1,"maximum":100,"default":50}},{"name":"offset","in":"query","required":false,"description":"Offset til paginering","schema":{"type":"integer","minimum":0,"default":0}},{"name":"sortBy","in":"query","required":false,"description":"Sorter efter feltet","schema":{"type":"string","enum":["created_at","last_message_at"],"default":"last_message_at"}},{"name":"sortOrder","in":"query","required":false,"description":"Sorterings retning","schema":{"type":"string","enum":["asc","desc"],"default":"desc"}}],"responses":{"200":{"description":"Agent samtaler hentet succesfuldt","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentConversationsResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/gmail/oauth/authorize":{"get":{"summary":"Gmail OAuth authorization","description":"Start Gmail OAuth authorization flow for email access. Redirects to Google OAuth consent screen.","tags":["Gmail Integration","OAuth"],"security":[{"SessionAuth":[]}],"parameters":[{"name":"redirect_uri","in":"query","required":false,"description":"Redirect URI efter successful authorization","schema":{"type":"string","format":"uri","default":"/dashboard"}},{"name":"scopes","in":"query","required":false,"description":"Gmail API scopes to request (comma-separated)","schema":{"type":"string","default":"gmail.readonly,gmail.send,gmail.modify"}}],"responses":{"302":{"description":"Redirect til Google OAuth consent screen","headers":{"Location":{"description":"Google OAuth URL","schema":{"type":"string","format":"uri"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/gmail/oauth/callback":{"get":{"summary":"Gmail OAuth callback","description":"Håndter OAuth callback fra Google og exchange authorization code for access tokens.","tags":["Gmail Integration","OAuth"],"parameters":[{"name":"code","in":"query","required":true,"description":"Authorization code fra Google OAuth","schema":{"type":"string"}},{"name":"state","in":"query","required":false,"description":"State parameter for CSRF protection","schema":{"type":"string"}},{"name":"error","in":"query","required":false,"description":"Error code if authorization failed","schema":{"type":"string"}}],"responses":{"302":{"description":"Redirect efter successful token exchange","headers":{"Location":{"description":"Redirect URL (typically /dashboard)","schema":{"type":"string","format":"uri"}}}},"400":{"description":"Invalid authorization code eller OAuth error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/gmail/accounts":{"get":{"summary":"List Gmail accounts","description":"Hent alle Gmail accounts for authenticated user med connection status og sync info.","tags":["Gmail Integration","Accounts"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"active_only","in":"query","required":false,"description":"Kun vis aktive Gmail accounts","schema":{"type":"boolean","default":false}}],"responses":{"200":{"description":"List af Gmail accounts","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GmailAccountsResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimited"}}},"post":{"summary":"Add Gmail account","description":"Tilføj ny Gmail account via OAuth flow eller manual configuration.","tags":["Gmail Integration","Accounts"],"security":[{"ApiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddGmailAccountRequest"}}}},"responses":{"201":{"description":"Gmail account tilføjet successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GmailAccountResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"409":{"description":"Gmail account already exists","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/gmail/accounts/{id}":{"get":{"summary":"Get Gmail account details","description":"Hent detaljeret information om specifik Gmail account inklusiv sync status og metrics.","tags":["Gmail Integration","Accounts"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Gmail account ID","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Gmail account details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GmailAccountDetailsResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}},"put":{"summary":"Update Gmail account","description":"Opdater Gmail account settings og sync configuration.","tags":["Gmail Integration","Accounts"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Gmail account ID","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateGmailAccountRequest"}}}},"responses":{"200":{"description":"Gmail account updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GmailAccountResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}},"delete":{"summary":"Remove Gmail account","description":"Fjern Gmail account og deactivate email sync. Eksisterende conversations bevares.","tags":["Gmail Integration","Accounts"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Gmail account ID","schema":{"type":"string","format":"uuid"}},{"name":"revoke_tokens","in":"query","required":false,"description":"Revoke OAuth tokens from Google","schema":{"type":"boolean","default":true}}],"responses":{"204":{"description":"Gmail account fjernet successfully"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/gmail/accounts/{id}/refresh":{"post":{"summary":"Refresh Gmail account tokens","description":"Forny OAuth access tokens for Gmail account ved hjælp af refresh token.","tags":["Gmail Integration","Accounts"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Gmail account ID","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Tokens refreshed successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TokenRefreshResponse"}}}},"400":{"description":"Refresh token invalid eller expired","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/webhooks/gmail":{"post":{"summary":"Gmail webhook handler","description":"Håndter Gmail Pub/Sub webhook notifikationer for real-time email processing","tags":["Webhooks","Gmail Integration"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GmailWebhookPayload"}}}},"responses":{"200":{"description":"Gmail webhook processed succesfuldt","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/webhooks/gmail/verify":{"get":{"summary":"Gmail webhook verification","description":"Gmail webhook subscription verifikation endpoint for Google Cloud Pub/Sub","tags":["Webhooks","Gmail Integration"],"parameters":[{"name":"token","in":"query","required":true,"description":"Verifikations token fra Google Cloud Pub/Sub","schema":{"type":"string"}}],"responses":{"200":{"description":"Webhook subscription verificeret","content":{"text/plain":{"schema":{"type":"string"}}}},"400":{"$ref":"#/components/responses/BadRequest"}}},"post":{"summary":"Gmail webhook verification (POST)","description":"Alternative POST metode for Gmail webhook verifikation","tags":["Webhooks","Gmail Integration"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GmailWebhookVerificationRequest"}}}},"responses":{"200":{"description":"Webhook subscription verificeret","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"}}}},"/cron/poll-emails":{"post":{"summary":"Scheduled email polling","description":"Automatisk email polling for alle brugere (Vercel Cron job)","tags":["Email Management","Cron Jobs"],"security":[{"BearerAuth":[]}],"responses":{"200":{"description":"Email polling gennemført succesfuldt","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailPollingResultResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/trigger-polling":{"get":{"summary":"Manual email polling trigger (GET)","description":"Manuel udløser af email polling for test og debugging","tags":["Email Management","Development"],"security":[{"SessionAuth":[]}],"responses":{"200":{"description":"Email polling startet","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailPollingResultResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}},"post":{"summary":"Manual email polling trigger","description":"Manuel udløser af email polling for specifik bruger eller alle brugere","tags":["Email Management","Administration"],"security":[{"SessionAuth":[]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TriggerPollingRequest"}}}},"responses":{"200":{"description":"Email polling gennemført","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailPollingResultResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/test-email-polling":{"post":{"summary":"Test email polling","description":"Test email polling funktionalitet for specifik bruger (udvikling/debugging)","tags":["Email Management","Development","Testing"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TestEmailPollingRequest"}}}},"responses":{"200":{"description":"Email polling test gennemført","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TestEmailPollingResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"500":{"$ref":"#/components/responses/InternalServerError"}}}},"/satisfaction/submit":{"get":{"summary":"Get satisfaction rating","description":"Hent eksisterende satisfaction rating for en samtale","tags":["Satisfaction Surveys","Customer Feedback"],"parameters":[{"name":"conversationId","in":"query","required":true,"description":"Samtale ID","schema":{"type":"string","format":"uuid"}},{"name":"rating","in":"query","required":false,"description":"Filtrer efter specifik rating","schema":{"type":"integer","minimum":1,"maximum":5}}],"responses":{"200":{"description":"Satisfaction rating hentet","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SatisfactionRatingResponse"}}}},"404":{"$ref":"#/components/responses/NotFound"}}},"post":{"summary":"Submit satisfaction rating","description":"Indsend kunde satisfaction rating og feedback for en samtale","tags":["Satisfaction Surveys","Customer Feedback"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubmitSatisfactionRequest"}}}},"responses":{"201":{"description":"Satisfaction rating gemt succesfuldt","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SatisfactionRatingResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/satisfaction/request":{"post":{"summary":"Request satisfaction survey","description":"Send satisfaction survey email til kunde for afsluttet samtale","tags":["Satisfaction Surveys","Email Communication"],"security":[{"SessionAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RequestSatisfactionSurveyRequest"}}}},"responses":{"200":{"description":"Satisfaction survey email sendt","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/api-keys":{"get":{"summary":"List API keys","description":"Hent brugerens API keys (kræver session authentication)","tags":["API Keys"],"security":[{"SessionAuth":[]}],"responses":{"200":{"description":"List of API keys","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiKeysResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}},"post":{"summary":"Create API key","description":"Generer en ny API key med specificerede scopes","tags":["API Keys"],"security":[{"SessionAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateApiKeyRequest"}}}},"responses":{"201":{"description":"API key created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiKeyResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/api-keys/{id}":{"delete":{"summary":"Deactivate API key","description":"Deaktiver en API key (soft delete)","tags":["API Keys"],"security":[{"SessionAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"description":"API key ID","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"API key deactivated successfully","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"message":{"type":"string","example":"API key deactivated successfully"}}},"meta":{"type":"object","properties":{"version":{"type":"string"}}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/webhooks":{"get":{"summary":"List webhooks","description":"Hent brugerens webhooks (kræver session authentication)","tags":["Webhooks"],"security":[{"SessionAuth":[]}],"responses":{"200":{"description":"List of webhooks","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhooksResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}},"post":{"summary":"Create webhook","description":"Opret en ny webhook til real-time notifikationer","tags":["Webhooks"],"security":[{"SessionAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateWebhookRequest"}}}},"responses":{"201":{"description":"Webhook created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/webhooks/{id}":{"delete":{"summary":"Deactivate webhook","description":"Deaktiver en webhook (soft delete)","tags":["Webhooks"],"security":[{"SessionAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Webhook ID","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Webhook deactivated successfully","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"message":{"type":"string","example":"Webhook \"Production Notifications\" deactivated successfully"}}},"meta":{"type":"object","properties":{"version":{"type":"string"}}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/bookings":{"get":{"summary":"List bookings","description":"Hent alle bookings med filtering muligheder. Understøtter dato range, status og agent filtrering.","tags":["Bookings"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"start_date","in":"query","description":"Filtrer bookings fra denne dato (ISO 8601)","schema":{"type":"string","format":"date","example":"2024-08-27"}},{"name":"end_date","in":"query","description":"Filtrer bookings til denne dato (ISO 8601)","schema":{"type":"string","format":"date","example":"2024-09-27"}},{"name":"status","in":"query","description":"Filtrer på booking status","schema":{"type":"string","enum":["scheduled","confirmed","cancelled","completed"],"example":"confirmed"}},{"name":"agent_id","in":"query","description":"Filtrer på specifik AI agent","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"List of bookings","headers":{"X-Total-Count":{"description":"Antal bookings returneret","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BookingsResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimited"}}},"post":{"summary":"Create booking","description":"Opret en ny booking med automatisk konflikt detektion og mulighed for auto-confirmation baseret på AI confidence score.","tags":["Bookings"],"security":[{"ApiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateBookingRequest"}}}},"responses":{"201":{"description":"Booking created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BookingCreatedResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"409":{"description":"Booking conflict - time slot already booked","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Error"},{"type":"object","properties":{"conflicting_bookings":{"type":"array","items":{"$ref":"#/components/schemas/Booking"}}}}]}}}},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/calendar/events":{"get":{"summary":"Get calendar events","description":"Hent kalenderhændelser inklusiv bookings, tilgængelighed og agent information for en dato range.","tags":["Calendar"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"start_date","in":"query","required":true,"description":"Start dato for kalendervisning (ISO 8601)","schema":{"type":"string","format":"date","example":"2024-08-27"}},{"name":"end_date","in":"query","required":true,"description":"Slut dato for kalendervisning (ISO 8601)","schema":{"type":"string","format":"date","example":"2024-09-03"}},{"name":"include_availability","in":"query","description":"Inkluder agent tilgængelighed i response","schema":{"type":"boolean","default":true}},{"name":"agent_ids","in":"query","description":"Filtrer på specifikke agents (comma-separated UUIDs)","schema":{"type":"string","example":"uuid1,uuid2,uuid3"}}],"responses":{"200":{"description":"Calendar events and availability data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CalendarEventsResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/calendar/ai-booking":{"post":{"summary":"AI-powered booking analysis","description":"Analyser email indhold for booking requests og returner intelligent booking forslag med AI confidence scoring.","tags":["Calendar","AI"],"security":[{"ApiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AIBookingRequest"}}}},"responses":{"200":{"description":"AI booking analysis complete","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AIBookingResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"description":"Agent not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"$ref":"#/components/responses/RateLimited"}}},"get":{"summary":"AI booking statistics","description":"Hent statistikker for AI-powered bookings inklusiv success rate og confidence metrics.","tags":["Calendar","AI","Analytics"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"agent_id","in":"query","required":true,"description":"AI agent ID for at hente statistikker","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"AI booking statistics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AIBookingStatsResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/calendar/agents-availability":{"get":{"summary":"Multi-agent availability","description":"Hent kombineret availability for multiple agents med time slot conflicts og optimal scheduling.","tags":["Calendar","Availability","Multi-Agent"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"agent_ids","in":"query","required":true,"description":"Comma-separated list of agent IDs","schema":{"type":"string"},"example":"uuid1,uuid2,uuid3"},{"name":"start_date","in":"query","required":true,"description":"Start date for availability check","schema":{"type":"string","format":"date"}},{"name":"end_date","in":"query","required":true,"description":"End date for availability check","schema":{"type":"string","format":"date"}},{"name":"include_conflicts","in":"query","required":false,"description":"Include time slots with conflicts between agents","schema":{"type":"boolean","default":false}}],"responses":{"200":{"description":"Multi-agent availability data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MultiAgentAvailabilityResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/calendar/blackout":{"get":{"summary":"Get calendar blackout periods","description":"Hent alle blackout periods for calendar system med agent-specific og system-wide restrictions.","tags":["Calendar","Availability"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"start_date","in":"query","required":false,"description":"Filter from start date","schema":{"type":"string","format":"date"}},{"name":"end_date","in":"query","required":false,"description":"Filter to end date","schema":{"type":"string","format":"date"}},{"name":"agent_id","in":"query","required":false,"description":"Filter by specific agent","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Calendar blackout periods","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CalendarBlackoutResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}},"post":{"summary":"Create calendar blackout period","description":"Opret ny calendar blackout period for at blokere booking i specifikke tidsperioder.","tags":["Calendar","Availability"],"security":[{"ApiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateCalendarBlackoutRequest"}}}},"responses":{"201":{"description":"Calendar blackout period created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CalendarBlackoutPeriod"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/blackout":{"get":{"summary":"Get system blackout periods","description":"Hent alle system-wide blackout periods der påvirker hele Agently platform.","tags":["System","Availability"],"security":[{"AdminAuth":[]}],"parameters":[{"name":"active_only","in":"query","required":false,"description":"Kun vis aktive blackout periods","schema":{"type":"boolean","default":false}}],"responses":{"200":{"description":"System blackout periods","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SystemBlackoutResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}},"post":{"summary":"Create system blackout","description":"Opret system-wide blackout period for vedligeholdelse eller nødsituationer.","tags":["System","Availability"],"security":[{"AdminAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateSystemBlackoutRequest"}}}},"responses":{"201":{"description":"System blackout created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SystemBlackoutPeriod"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/vacation":{"get":{"summary":"Get agent vacations","description":"Hent alle vacation periods for AI agents med automatic handover og coverage management.","tags":["Agents","Vacation"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"agent_id","in":"query","required":false,"description":"Filter by specific agent","schema":{"type":"string","format":"uuid"}},{"name":"start_date","in":"query","required":false,"description":"Filter from start date","schema":{"type":"string","format":"date"}},{"name":"end_date","in":"query","required":false,"description":"Filter to end date","schema":{"type":"string","format":"date"}}],"responses":{"200":{"description":"Agent vacation periods","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VacationPeriodsResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}},"post":{"summary":"Create agent vacation","description":"Schedule vacation period for AI agent med automatic coverage assignment og customer notifications.","tags":["Agents","Vacation"],"security":[{"ApiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateVacationRequest"}}}},"responses":{"201":{"description":"Vacation period created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VacationPeriod"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"409":{"description":"Vacation period conflicts with existing booking","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/vacation/{id}":{"get":{"summary":"Get vacation details","description":"Hent detaljeret information om specifik vacation period inklusiv coverage status.","tags":["Agents","Vacation"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Vacation period ID","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Vacation period details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VacationDetailsResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}},"put":{"summary":"Update vacation period","description":"Opdater vacation period med automatic re-scheduling af affected bookings.","tags":["Agents","Vacation"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Vacation period ID","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateVacationRequest"}}}},"responses":{"200":{"description":"Vacation period updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VacationPeriod"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}},"delete":{"summary":"Cancel vacation period","description":"Annuller vacation period og restore agent availability for affected dates.","tags":["Agents","Vacation"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Vacation period ID","schema":{"type":"string","format":"uuid"}},{"name":"notify_customers","in":"query","required":false,"description":"Send notification til customers with affected bookings","schema":{"type":"boolean","default":true}}],"responses":{"204":{"description":"Vacation period cancelled successfully"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/bookings/auto-confirm-pending":{"post":{"summary":"Auto-confirm pending bookings","description":"Køre auto-confirmation logic på alle pending bookings baseret på agent konfiguration og AI confidence scores.","tags":["Bookings","AI"],"security":[{"ApiKeyAuth":[]}],"responses":{"200":{"description":"Auto-confirmation process completed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AutoConfirmResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/admin/users":{"get":{"summary":"Get system users for admin dashboard","description":"Hent liste over alle system brugere med subscription status, usage metrics og admin kontrols. Kun tilgængelig for admin brugere.","tags":["Admin","Users"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"page","in":"query","description":"Side nummer for paginering","required":false,"schema":{"type":"integer","default":1,"minimum":1}},{"name":"limit","in":"query","description":"Antal brugere per side","required":false,"schema":{"type":"integer","default":50,"minimum":1,"maximum":100}},{"name":"status","in":"query","description":"Filter brugere efter subscription status","required":false,"schema":{"type":"string","enum":["active","inactive","trial","cancelled","suspended"]}},{"name":"search","in":"query","description":"Søg i bruger email eller navn","required":false,"schema":{"type":"string","maxLength":100}},{"name":"sort","in":"query","description":"Sortering af resultater","required":false,"schema":{"type":"string","enum":["created_at","last_activity","email_usage","subscription_value"],"default":"created_at"}},{"name":"order","in":"query","description":"Sorteringsretning","required":false,"schema":{"type":"string","enum":["asc","desc"],"default":"desc"}}],"responses":{"200":{"description":"System brugere hentet succesfuldt","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminUsersResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"Adgang nægtet - admin rettigheder påkrævet","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","example":"Admin rettigheder påkrævet"},"code":{"type":"string","example":"ADMIN_ACCESS_REQUIRED"}}}}}},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/admin/analytics":{"get":{"summary":"Get system analytics for admin dashboard","description":"Hent omfattende system analytics inklusiv bruger metrics, email volume, AI usage, subscription revenue og performance statistikker.","tags":["Admin","Analytics"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"period","in":"query","description":"Tidsperiode for analytics data","required":false,"schema":{"type":"string","enum":["7d","30d","90d","1y","all"],"default":"30d"}},{"name":"granularity","in":"query","description":"Data granularitet for time-series","required":false,"schema":{"type":"string","enum":["hour","day","week","month"],"default":"day"}},{"name":"metrics","in":"query","description":"Komma-separeret liste af metrics der skal inkluderes","required":false,"schema":{"type":"string","example":"users,emails,revenue,ai_usage"}}],"responses":{"200":{"description":"System analytics hentet succesfuldt","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminAnalyticsResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"Adgang nægtet - admin rettigheder påkrævet","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","example":"Admin rettigheder påkrævet"},"code":{"type":"string","example":"ADMIN_ACCESS_REQUIRED"}}}}}},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/admin/openai-stats":{"get":{"summary":"Get OpenAI API usage statistics","description":"Hent detaljerede OpenAI API usage statistikker inklusiv token consumption, costs, model usage og performance metrics for cost optimization.","tags":["Admin","AI","Analytics"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"period","in":"query","description":"Tidsperiode for OpenAI statistikker","required":false,"schema":{"type":"string","enum":["today","7d","30d","90d"],"default":"30d"}},{"name":"group_by","in":"query","description":"Gruppér statistikker efter","required":false,"schema":{"type":"string","enum":["model","user","agent","day","hour"],"default":"day"}},{"name":"include_costs","in":"query","description":"Inkludér cost analysis i response","required":false,"schema":{"type":"boolean","default":true}}],"responses":{"200":{"description":"OpenAI statistics hentet succesfuldt","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OpenAIStatsResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"Adgang nægtet - admin rettigheder påkrævet","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","example":"Admin rettigheder påkrævet"},"code":{"type":"string","example":"ADMIN_ACCESS_REQUIRED"}}}}}},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/admin/health":{"get":{"summary":"Get comprehensive system health status","description":"Hent detaljeret system health monitoring inklusiv database status, external service connectivity, performance metrics og alert status.","tags":["Admin","Monitoring","Health"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"detailed","in":"query","description":"Inkludér detaljerede service checks","required":false,"schema":{"type":"boolean","default":false}},{"name":"include_metrics","in":"query","description":"Inkludér performance metrics","required":false,"schema":{"type":"boolean","default":true}}],"responses":{"200":{"description":"System health status","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminHealthResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"Adgang nægtet - admin rettigheder påkrævet","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","example":"Admin rettigheder påkrævet"},"code":{"type":"string","example":"ADMIN_ACCESS_REQUIRED"}}}}}},"429":{"$ref":"#/components/responses/RateLimited"},"503":{"description":"Service unavailable - system health degraded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminHealthResponse"}}}}}}},"/test/agent-response":{"post":{"summary":"Test AI agent response generation","description":"Test endpoint til udvikling og debugging af AI agent responses. Bruges til at verificere agent konfiguration og response kvalitet.","tags":["Test","Debug"],"security":[{"ApiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["agent_id","test_message"],"properties":{"agent_id":{"type":"string","format":"uuid","description":"ID på AI agent der skal testes"},"test_message":{"type":"string","description":"Test besked til agent processing","example":"Hej, jeg vil gerne høre mere om jeres produkter"},"conversation_history":{"type":"array","items":{"type":"object","properties":{"role":{"type":"string","enum":["user","assistant"]},"content":{"type":"string"}}},"description":"Optional conversation context for testing"},"override_settings":{"type":"object","properties":{"temperature":{"type":"number","minimum":0,"maximum":2},"max_tokens":{"type":"integer","minimum":1,"maximum":2000},"response_style":{"type":"string","enum":["professional","casual","technical"]}},"description":"Temporary agent settings override for testing"}}}}}},"responses":{"200":{"description":"Agent response test results","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentTestResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/test/openai":{"post":{"summary":"Test OpenAI API connection","description":"Test endpoint til verificering af OpenAI API forbindelse, quota limits og response quality. Bruges til system monitoring og debugging.","tags":["Test","Debug"],"security":[{"ApiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"test_prompt":{"type":"string","default":"Test OpenAI connection","description":"Custom test prompt for OpenAI API"},"model":{"type":"string","enum":["gpt-4","gpt-4-turbo","gpt-3.5-turbo"],"default":"gpt-4","description":"OpenAI model til test"},"include_usage_stats":{"type":"boolean","default":true,"description":"Include token usage and cost information"}}}}}},"responses":{"200":{"description":"OpenAI connection test results","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OpenAITestResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"description":"OpenAI API connection failed","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"openai_error":{"type":"string"},"quota_exceeded":{"type":"boolean"}}}}}}}}},"/test/knowledge-edit":{"post":{"summary":"Test agent knowledge base editing","description":"Test endpoint til verificering af agent knowledge base updates, retrieval accuracy og content processing.","tags":["Test","Debug"],"security":[{"ApiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["agent_id","test_content"],"properties":{"agent_id":{"type":"string","format":"uuid","description":"ID på AI agent hvis knowledge base skal testes"},"test_content":{"type":"string","description":"Test content til knowledge base processing","example":"Vores produkter inkluderer CRM software til danske virksomheder"},"operation":{"type":"string","enum":["add","update","delete","search"],"default":"add","description":"Knowledge base operation to test"},"knowledge_category":{"type":"string","enum":["products","policies","procedures","faq"],"description":"Category for knowledge organization"},"test_query":{"type":"string","description":"Query to test knowledge retrieval (for search operations)","example":"Hvad er priserne på CRM software?"}}}}}},"responses":{"200":{"description":"Knowledge base test results","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KnowledgeTestResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/agents/{id}/knowledge/upload-file":{"post":{"summary":"Upload fil til agent knowledge base","description":"Upload en fil (PDF, DOC, TXT, etc.) til en agents knowledge base for at udvide agentens viden og kontekst.","tags":["Advanced Agent Features"],"parameters":[{"name":"id","in":"path","required":true,"description":"Agent ID som filen uploades til","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","properties":{"file":{"type":"string","format":"binary","description":"Fil der skal uploades (PDF, DOC, DOCX, TXT, MD)"},"title":{"type":"string","description":"Valgfri titel til filen i knowledge base","maxLength":200},"tags":{"type":"array","items":{"type":"string"},"description":"Tags til at kategorisere filen"},"is_public":{"type":"boolean","default":false,"description":"Om filen er tilgængelig for andre agents"},"processing_instructions":{"type":"string","description":"Specielle instruktioner til hvordan agenten skal bruge denne viden","maxLength":1000}}}}}},"responses":{"200":{"description":"Fil uploaded og processeret succesfuldt","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KnowledgeFileResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"413":{"description":"Fil for stor (max 10MB)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","example":"Fil for stor - maksimum 10MB tilladt"}}}}}},"415":{"description":"Ikke-understøttet filtype","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","example":"Filtype ikke understøttet - kun PDF, DOC, DOCX, TXT, MD tilladt"}}}}}},"429":{"$ref":"#/components/responses/RateLimited"}},"security":[{"ApiKeyAuth":[]}]}},"/agents/{id}/knowledge/{itemId}":{"get":{"summary":"Hent specifik knowledge item","description":"Hent detaljer om en specifik knowledge item fra agents knowledge base.","tags":["Advanced Agent Features"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"itemId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"include_content","in":"query","schema":{"type":"boolean","default":false},"description":"Om filens fulde indhold skal inkluderes"}],"responses":{"200":{"description":"Knowledge item detaljer","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KnowledgeItem"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}},"security":[{"ApiKeyAuth":[]}]},"put":{"summary":"Opdater knowledge item","description":"Opdater en eksisterende knowledge item med ny information eller ændre tags/titel.","tags":["Advanced Agent Features"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"itemId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"title":{"type":"string","maxLength":200},"tags":{"type":"array","items":{"type":"string"}},"content":{"type":"string","description":"Nyt indhold til knowledge item"},"processing_instructions":{"type":"string","maxLength":1000},"is_active":{"type":"boolean","description":"Om knowledge item er aktivt i agent responses"}}}}}},"responses":{"200":{"description":"Knowledge item opdateret","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KnowledgeItem"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}},"security":[{"ApiKeyAuth":[]}]},"delete":{"summary":"Slet knowledge item","description":"Slet en knowledge item fra agents knowledge base.","tags":["Advanced Agent Features"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"itemId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Knowledge item slettet","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"Knowledge item slettet succesfuldt"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}},"security":[{"ApiKeyAuth":[]}]}},"/agents/{id}/unavailable/{unavailableId}":{"get":{"summary":"Hent unavailability periode","description":"Hent detaljer om en specifik unavailability periode for en agent.","tags":["Advanced Agent Features"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"unavailableId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Unavailability periode detaljer","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentUnavailability"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}},"security":[{"ApiKeyAuth":[]}]},"put":{"summary":"Opdater unavailability periode","description":"Opdater en eksisterende unavailability periode for en agent.","tags":["Advanced Agent Features"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"unavailableId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"title":{"type":"string","maxLength":100},"start_date":{"type":"string","format":"date-time"},"end_date":{"type":"string","format":"date-time"},"reason":{"type":"string","enum":["vacation","sick","training","maintenance","other"]},"description":{"type":"string","maxLength":500},"is_recurring":{"type":"boolean","default":false},"recurrence_pattern":{"type":"object","properties":{"frequency":{"type":"string","enum":["daily","weekly","monthly","yearly"]},"interval":{"type":"integer","minimum":1},"days_of_week":{"type":"array","items":{"type":"string","enum":["mon","tue","wed","thu","fri","sat","sun"]}}}},"auto_reply_message":{"type":"string","description":"Automatisk svar besked til kunder under unavailability","maxLength":500}}}}}},"responses":{"200":{"description":"Unavailability periode opdateret","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentUnavailability"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}},"security":[{"ApiKeyAuth":[]}]},"delete":{"summary":"Slet unavailability periode","description":"Slet en unavailability periode for en agent.","tags":["Advanced Agent Features"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"unavailableId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Unavailability periode slettet","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"Unavailability periode slettet succesfuldt"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}},"security":[{"ApiKeyAuth":[]}]}},"/performance-alerts":{"get":{"summary":"List alle performance alerts","description":"Hent alle performance alerts for brugeren med filtering og sortering muligheder.","tags":["Advanced Agent Features"],"parameters":[{"name":"agent_id","in":"query","schema":{"type":"string","format":"uuid"},"description":"Filter alerts for specifik agent"},{"name":"alert_type","in":"query","schema":{"type":"string","enum":["response_time_high","error_rate_high","satisfaction_low","volume_anomaly"]},"description":"Filter efter alert type"},{"name":"status","in":"query","schema":{"type":"string","enum":["active","acknowledged","resolved"],"default":"active"}},{"name":"severity","in":"query","schema":{"type":"string","enum":["low","medium","high","critical"]}},{"name":"from_date","in":"query","schema":{"type":"string","format":"date-time"},"description":"Alerts fra denne dato"},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":20}},{"name":"offset","in":"query","schema":{"type":"integer","minimum":0,"default":0}}],"responses":{"200":{"description":"Performance alerts liste","content":{"application/json":{"schema":{"type":"object","properties":{"alerts":{"type":"array","items":{"$ref":"#/components/schemas/PerformanceAlert"}},"total_count":{"type":"integer"},"active_count":{"type":"integer"},"critical_count":{"type":"integer"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimited"}},"security":[{"ApiKeyAuth":[]}]},"post":{"summary":"Opret ny performance alert regel","description":"Opret en ny performance alert regel der overvåger agent performance og sender notifikationer.","tags":["Advanced Agent Features"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name","alert_type","threshold_value"],"properties":{"name":{"type":"string","maxLength":100,"description":"Navn på alert reglen"},"description":{"type":"string","maxLength":500},"alert_type":{"type":"string","enum":["response_time_high","error_rate_high","satisfaction_low","volume_anomaly"]},"agent_ids":{"type":"array","items":{"type":"string","format":"uuid"},"description":"Specifik agents at overvåge, eller tom for alle agents"},"threshold_value":{"type":"number","description":"Threshold værdi der trigger alert"},"threshold_comparison":{"type":"string","enum":["greater_than","less_than","equals"],"default":"greater_than"},"time_window_minutes":{"type":"integer","minimum":5,"maximum":1440,"default":60,"description":"Tidsvindue for alert evaluering i minutter"},"severity":{"type":"string","enum":["low","medium","high","critical"],"default":"medium"},"notification_channels":{"type":"array","items":{"type":"string","enum":["email","sms","webhook","dashboard"]},"default":["email","dashboard"]},"webhook_url":{"type":"string","format":"uri","description":"Webhook URL for notifikationer"},"is_active":{"type":"boolean","default":true}}}}}},"responses":{"201":{"description":"Performance alert regel oprettet","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PerformanceAlert"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimited"}},"security":[{"ApiKeyAuth":[]}]}},"/performance-alerts/{id}":{"get":{"summary":"Hent specifik performance alert","description":"Hent detaljer om en specifik performance alert regel.","tags":["Advanced Agent Features"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Performance alert detaljer","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PerformanceAlert"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}},"security":[{"ApiKeyAuth":[]}]},"put":{"summary":"Opdater performance alert regel","description":"Opdater en eksisterende performance alert regel.","tags":["Advanced Agent Features"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","maxLength":100},"description":{"type":"string","maxLength":500},"threshold_value":{"type":"number"},"threshold_comparison":{"type":"string","enum":["greater_than","less_than","equals"]},"time_window_minutes":{"type":"integer","minimum":5,"maximum":1440},"severity":{"type":"string","enum":["low","medium","high","critical"]},"notification_channels":{"type":"array","items":{"type":"string","enum":["email","sms","webhook","dashboard"]}},"webhook_url":{"type":"string","format":"uri"},"is_active":{"type":"boolean"}}}}}},"responses":{"200":{"description":"Performance alert regel opdateret","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PerformanceAlert"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}},"security":[{"ApiKeyAuth":[]}]},"delete":{"summary":"Slet performance alert regel","description":"Slet en performance alert regel.","tags":["Advanced Agent Features"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Performance alert regel slettet","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"Performance alert regel slettet succesfuldt"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}},"security":[{"ApiKeyAuth":[]}]}},"/performance-alerts/stats":{"get":{"summary":"Performance alert statistikker","description":"Hent statistikker og aggregeret data for performance alerts.","tags":["Advanced Agent Features"],"parameters":[{"name":"period","in":"query","schema":{"type":"string","enum":["1h","24h","7d","30d"],"default":"24h"},"description":"Tidsperiode for statistikker"},{"name":"agent_id","in":"query","schema":{"type":"string","format":"uuid"},"description":"Filter statistikker for specifik agent"}],"responses":{"200":{"description":"Performance alert statistikker","content":{"application/json":{"schema":{"type":"object","properties":{"period":{"type":"string"},"total_alerts":{"type":"integer"},"active_alerts":{"type":"integer"},"resolved_alerts":{"type":"integer"},"alert_breakdown":{"type":"object","properties":{"response_time_high":{"type":"integer"},"error_rate_high":{"type":"integer"},"satisfaction_low":{"type":"integer"},"volume_anomaly":{"type":"integer"}}},"severity_breakdown":{"type":"object","properties":{"low":{"type":"integer"},"medium":{"type":"integer"},"high":{"type":"integer"},"critical":{"type":"integer"}}},"avg_resolution_time_minutes":{"type":"number"},"most_affected_agents":{"type":"array","items":{"type":"object","properties":{"agent_id":{"type":"string","format":"uuid"},"agent_name":{"type":"string"},"alert_count":{"type":"integer"}}}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimited"}},"security":[{"ApiKeyAuth":[]}]}},"/providers/test":{"post":{"summary":"Test email provider forbindelse","description":"Test forbindelsen til en email provider (Gmail, Outlook, IMAP, SMTP) og verificer konfiguration.","tags":["Advanced Agent Features"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["provider_type"],"properties":{"provider_type":{"type":"string","enum":["gmail","outlook","imap","smtp"]},"provider_settings":{"type":"object","description":"Provider-specifik konfiguration","properties":{"email":{"type":"string","format":"email"},"host":{"type":"string"},"port":{"type":"integer"},"username":{"type":"string"},"password":{"type":"string"},"refresh_token":{"type":"string"},"access_token":{"type":"string"},"use_ssl":{"type":"boolean","default":true},"use_tls":{"type":"boolean","default":true}}},"test_operations":{"type":"array","items":{"type":"string","enum":["connect","authenticate","read_inbox","send_test_email","webhook_setup"]},"default":["connect","authenticate","read_inbox"]},"test_email_recipient":{"type":"string","format":"email","description":"Email til test af udsendelse (valgfri)"}}}}}},"responses":{"200":{"description":"Provider test resultater","content":{"application/json":{"schema":{"type":"object","properties":{"provider_type":{"type":"string"},"overall_status":{"type":"string","enum":["success","partial","failed"]},"test_results":{"type":"array","items":{"type":"object","properties":{"operation":{"type":"string"},"status":{"type":"string","enum":["success","failed","skipped"]},"duration_ms":{"type":"integer"},"message":{"type":"string"},"details":{"type":"object"}}}},"connection_info":{"type":"object","properties":{"server_info":{"type":"string"},"supported_features":{"type":"array","items":{"type":"string"}},"quota_info":{"type":"object","properties":{"total_messages":{"type":"integer"},"used_storage_mb":{"type":"number"}}}}},"recommendations":{"type":"array","items":{"type":"string"},"description":"Anbefalinger til forbedring af konfiguration"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimited"}},"security":[{"ApiKeyAuth":[]}]}},"/debug-accounts":{"get":{"summary":"Debug email accounts tilstande","description":"Hent debug information for alle email accounts med detaljeret status og fejl diagnostics. Bruges til systemadministration og fejlsøgning.","tags":["Monitoring & System Health"],"parameters":[{"name":"user_id","in":"query","schema":{"type":"string","format":"uuid"},"description":"Filtrer debug info til specifik bruger (admin only)"},{"name":"provider","in":"query","schema":{"type":"string","enum":["gmail","outlook","imap","all"]},"description":"Filtrer efter email provider type"},{"name":"status_filter","in":"query","schema":{"type":"string","enum":["active","error","disconnected","quota_exceeded"]},"description":"Filtrer efter account status"},{"name":"include_credentials","in":"query","schema":{"type":"boolean","default":false},"description":"Include masked credential status (admin only)"}],"responses":{"200":{"description":"Account debug information hentet succesfuldt","content":{"application/json":{"schema":{"type":"object","properties":{"total_accounts":{"type":"integer","description":"Total antal email accounts"},"active_accounts":{"type":"integer","description":"Antal aktive accounts"},"error_accounts":{"type":"integer","description":"Antal accounts med fejl"},"provider_breakdown":{"type":"object","properties":{"gmail":{"type":"integer"},"outlook":{"type":"integer"},"imap":{"type":"integer"}}},"accounts":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"user_id":{"type":"string","format":"uuid"},"email":{"type":"string","format":"email"},"provider":{"type":"string"},"status":{"type":"string","enum":["active","error","disconnected","quota_exceeded"]},"last_sync":{"type":"string","format":"date-time"},"last_error":{"type":"string","nullable":true},"connection_health":{"type":"object","properties":{"can_connect":{"type":"boolean"},"can_send":{"type":"boolean"},"can_read":{"type":"boolean"},"quota_status":{"type":"string"},"rate_limit_status":{"type":"string"}}},"performance_metrics":{"type":"object","properties":{"avg_response_time_ms":{"type":"number"},"success_rate_percent":{"type":"number"},"daily_email_count":{"type":"integer"},"error_count_24h":{"type":"integer"}}}}}}}}}}},"403":{"description":"Ikke tilstrækkelige rettigheder til debug information"},"429":{"$ref":"#/components/responses/RateLimited"}},"security":[{"ApiKeyAuth":[]}]}},"/email-accounts/all":{"get":{"summary":"Hent overview af alle email accounts","description":"Administrator endpoint til at få overblik over alle email accounts på tværs af alle brugere. Inkluderer status, performance metrics og health checks.","tags":["Monitoring & System Health"],"parameters":[{"name":"page","in":"query","schema":{"type":"integer","minimum":1,"default":1},"description":"Side nummer for paginering"},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":25},"description":"Antal accounts per side"},{"name":"sort_by","in":"query","schema":{"type":"string","enum":["created_at","last_sync","email_count","error_rate"],"default":"last_sync"},"description":"Sorter resultater efter"},{"name":"sort_order","in":"query","schema":{"type":"string","enum":["asc","desc"],"default":"desc"},"description":"Sorteringsretning"},{"name":"provider_filter","in":"query","schema":{"type":"string","enum":["gmail","outlook","imap"]},"description":"Filtrer efter provider type"},{"name":"status_filter","in":"query","schema":{"type":"string","enum":["active","error","disconnected"]},"description":"Filtrer efter account status"},{"name":"health_check","in":"query","schema":{"type":"boolean","default":false},"description":"Kør live health check for alle accounts (langsom operation)"}],"responses":{"200":{"description":"Email accounts overview hentet succesfuldt","content":{"application/json":{"schema":{"type":"object","properties":{"pagination":{"type":"object","properties":{"current_page":{"type":"integer"},"per_page":{"type":"integer"},"total_pages":{"type":"integer"},"total_count":{"type":"integer"}}},"summary":{"type":"object","properties":{"total_accounts":{"type":"integer"},"active_accounts":{"type":"integer"},"error_accounts":{"type":"integer"},"avg_daily_emails":{"type":"number"},"total_emails_processed_today":{"type":"integer"}}},"accounts":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"user_email":{"type":"string","format":"email"},"account_email":{"type":"string","format":"email"},"provider":{"type":"string"},"status":{"type":"string"},"created_at":{"type":"string","format":"date-time"},"last_sync":{"type":"string","format":"date-time"},"stats":{"type":"object","properties":{"emails_today":{"type":"integer"},"emails_this_week":{"type":"integer"},"emails_this_month":{"type":"integer"},"avg_response_time_minutes":{"type":"number"},"success_rate_percent":{"type":"number"}}},"health_status":{"type":"object","nullable":true,"properties":{"is_healthy":{"type":"boolean"},"last_error":{"type":"string","nullable":true},"connection_test":{"type":"boolean"},"quota_remaining":{"type":"number","nullable":true},"checked_at":{"type":"string","format":"date-time"}},"description":"Kun inkluderet hvis health_check=true"}}}}}}}}},"403":{"description":"Ikke administrator rettigheder"},"429":{"$ref":"#/components/responses/RateLimited"}},"security":[{"ApiKeyAuth":[]}]}}},"components":{"schemas":{"HealthResponse":{"type":"object","properties":{"status":{"type":"string","enum":["healthy","degraded","error"],"description":"Overall system status"},"timestamp":{"type":"string","format":"date-time","description":"Health check timestamp"},"version":{"type":"string","example":"v1","description":"API version"},"checks":{"type":"object","properties":{"database":{"type":"boolean"},"redis":{"type":"boolean"},"api":{"type":"boolean"}}},"uptime":{"type":"number","description":"Server uptime i sekunder"}}},"Agent":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Unique agent identifier"},"name":{"type":"string","description":"Agent navn","example":"Sales Assistant"},"role":{"type":"string","enum":["sales","support","followup","custom"],"description":"Agent rolle"},"personality":{"type":"string","description":"Agent personlighed beskrivelse","example":"Professionel og hjælpsom"},"instructions":{"type":"string","description":"Detaljerede instruktioner til agenten","example":"Du er en sales assistant der hjælper kunder med produktforespørgsler"},"working_hours":{"type":"object","properties":{"start":{"type":"string","example":"09:00"},"end":{"type":"string","example":"17:00"},"timezone":{"type":"string","example":"Europe/Copenhagen"}}},"is_active":{"type":"boolean","description":"Om agenten er aktiv"},"created_at":{"type":"string","format":"date-time"}}},"AgentsResponse":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Agent"}},"meta":{"type":"object","properties":{"total":{"type":"integer"},"version":{"type":"string"}}}}},"AgentResponse":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Agent"},"meta":{"type":"object","properties":{"version":{"type":"string"}}}}},"CreateAgentRequest":{"type":"object","required":["name","role","instructions"],"properties":{"name":{"type":"string","description":"Agent navn","example":"Sales Assistant"},"role":{"type":"string","enum":["sales","support","followup","custom"],"description":"Agent rolle"},"personality":{"type":"string","description":"Agent personlighed (valgfri)","example":"Professionel og hjælpsom"},"instructions":{"type":"string","description":"Detaljerede instruktioner til agenten","example":"Du er en sales assistant der hjælper kunder med produktforespørgsler"},"working_hours":{"type":"object","properties":{"start":{"type":"string","example":"09:00"},"end":{"type":"string","example":"17:00"},"timezone":{"type":"string","example":"Europe/Copenhagen"}}}}},"UpdateAgentRequest":{"type":"object","properties":{"name":{"type":"string","description":"Agent navn","example":"Emma - Sales Assistant"},"role":{"type":"string","enum":["sales","support","followup","custom"],"description":"Agent rolle"},"personality":{"type":"string","description":"Agent personlighed","example":"Professionel og hjælpsom"},"instructions":{"type":"string","description":"Detaljerede instruktioner til agenten","example":"Du er en sales assistant der hjælper kunder med produktforespørgsler"},"working_hours":{"type":"object","properties":{"start":{"type":"string","example":"09:00"},"end":{"type":"string","example":"17:00"},"timezone":{"type":"string","example":"Europe/Copenhagen"}}},"is_active":{"type":"boolean","description":"Om agenten er aktiv"},"auto_confirm_bookings":{"type":"boolean","description":"Automatisk bekræftelse af bookings"},"auto_confirm_threshold":{"type":"number","minimum":0.5,"maximum":1,"description":"Minimum AI confidence score for auto-confirmation"},"color":{"type":"string","description":"Agent farve til UI visning","example":"#3B82F6"},"avatar_id":{"type":"integer","minimum":1,"maximum":16,"description":"Avatar ID (1-16)"},"email_signature":{"type":"string","description":"Email signatur template"}}},"AvailabilityResponse":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"agent_id":{"type":"string","format":"uuid"},"day_of_week":{"type":"integer","minimum":0,"maximum":6},"start_time":{"type":"string","example":"09:00"},"end_time":{"type":"string","example":"17:00"},"is_active":{"type":"boolean"},"created_at":{"type":"string","format":"date-time"}}}},"meta":{"type":"object","properties":{"total_slots":{"type":"integer"},"active_slots":{"type":"integer"},"weekly_hours":{"type":"number"},"timezone":{"type":"string"}}}}},"UpdateAvailabilityRequest":{"type":"object","required":["availability"],"properties":{"availability":{"type":"array","items":{"type":"object","required":["day_of_week","start_time","end_time"],"properties":{"day_of_week":{"type":"integer","minimum":0,"maximum":6,"description":"Ugedag (0=søndag, 6=lørdag)"},"start_time":{"type":"string","pattern":"^([0-1]?[0-9]|2[0-3]):[0-5][0-9]$","example":"09:00"},"end_time":{"type":"string","pattern":"^([0-1]?[0-9]|2[0-3]):[0-5][0-9]$","example":"17:00"}}}}}},"AgentMetricsResponse":{"type":"object","properties":{"data":{"type":"object","properties":{"period":{"type":"object","properties":{"start_date":{"type":"string","format":"date"},"end_date":{"type":"string","format":"date"},"total_days":{"type":"integer"}}},"conversation_metrics":{"type":"object","properties":{"total_conversations":{"type":"integer"},"active_conversations":{"type":"integer"},"resolved_conversations":{"type":"integer"},"escalated_conversations":{"type":"integer"},"resolution_rate":{"type":"number","minimum":0,"maximum":1},"escalation_rate":{"type":"number","minimum":0,"maximum":1}}},"response_metrics":{"type":"object","properties":{"avg_response_time":{"type":"number","description":"Gennemsnitlig responstid i sekunder"},"median_response_time":{"type":"number"},"response_rate":{"type":"number","minimum":0,"maximum":1}}},"satisfaction_metrics":{"type":"object","properties":{"avg_satisfaction":{"type":"number","minimum":1,"maximum":5},"total_ratings":{"type":"integer"},"satisfaction_distribution":{"type":"object","properties":{"1":{"type":"integer"},"2":{"type":"integer"},"3":{"type":"integer"},"4":{"type":"integer"},"5":{"type":"integer"}}}}},"booking_metrics":{"type":"object","properties":{"total_bookings":{"type":"integer"},"confirmed_bookings":{"type":"integer"},"auto_confirmed_bookings":{"type":"integer"},"cancelled_bookings":{"type":"integer"},"auto_confirm_rate":{"type":"number","minimum":0,"maximum":1}}}}}}},"ConversationsResponse":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"customer_email":{"type":"string","format":"email"},"subject":{"type":"string"},"status":{"type":"string","enum":["active","resolved","escalated"]},"message_count":{"type":"integer"},"last_message_at":{"type":"string","format":"date-time"},"created_at":{"type":"string","format":"date-time"},"is_manual_takeover":{"type":"boolean"},"satisfaction_rating":{"type":"integer","minimum":1,"maximum":5,"nullable":true}}}},"meta":{"type":"object","properties":{"total":{"type":"integer"},"active":{"type":"integer"},"resolved":{"type":"integer"},"escalated":{"type":"integer"},"limit":{"type":"integer"},"offset":{"type":"integer"},"has_more":{"type":"boolean"}}}}},"AutoBookingStatsResponse":{"type":"object","properties":{"data":{"type":"object","properties":{"statistics":{"type":"object","properties":{"total_requests":{"type":"integer"},"successful_bookings":{"type":"integer"},"failed_attempts":{"type":"integer"},"avg_confidence_score":{"type":"number"},"success_rate":{"type":"number","minimum":0,"maximum":1},"avg_processing_time":{"type":"number","description":"Millisekunder"}}},"recent_logs":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"customer_email":{"type":"string","format":"email"},"confidence_score":{"type":"number"},"result":{"type":"string","enum":["success","failed","insufficient_confidence"]},"processing_time":{"type":"number"},"created_at":{"type":"string","format":"date-time"},"error_message":{"type":"string","nullable":true}}}}}},"meta":{"type":"object","properties":{"period":{"type":"object","properties":{"start_date":{"type":"string","format":"date"},"end_date":{"type":"string","format":"date"}}}}}}},"AutoBookingRequest":{"type":"object","required":["customer_email","email_content"],"properties":{"customer_email":{"type":"string","format":"email","description":"Kundens email adresse"},"email_content":{"type":"string","description":"Email indhold til AI analyse","example":"Hej, jeg vil gerne booke et møde næste uge tirsdag omkring kl. 14. Mvh, Lars"},"customer_name":{"type":"string","description":"Kundens navn (valgfri)"},"subject":{"type":"string","description":"Email emne (valgfri)"},"confidence_threshold":{"type":"number","minimum":0.1,"maximum":1,"default":0.8,"description":"Minimum confidence score for automatisk booking"}}},"AutoBookingResponse":{"type":"object","properties":{"success":{"type":"boolean"},"analysis":{"type":"object","properties":{"confidence_score":{"type":"number"},"detected_intent":{"type":"string","enum":["booking_request","inquiry","complaint","other"]},"extracted_info":{"type":"object","properties":{"preferred_date":{"type":"string","nullable":true},"preferred_time":{"type":"string","nullable":true},"meeting_duration":{"type":"integer","nullable":true},"meeting_title":{"type":"string","nullable":true},"special_requirements":{"type":"string","nullable":true}}}}},"booking_result":{"type":"object","nullable":true,"properties":{"booking_id":{"type":"string","format":"uuid"},"scheduled_start":{"type":"string","format":"date-time"},"scheduled_end":{"type":"string","format":"date-time"},"status":{"type":"string","enum":["confirmed","pending"]}}},"ai_response":{"type":"string","description":"AI genereret svar til kunden"},"processing_time":{"type":"number","description":"Processing tid i millisekunder"}}},"BookingRulesResponse":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"agent_id":{"type":"string","format":"uuid"},"rule_type":{"type":"string","enum":["minimum_notice","maximum_advance","meeting_types","time_restrictions","customer_limits","buffer_override","approval_required"]},"rule_config":{"type":"object","description":"Regel konfiguration (varierer efter type)"},"is_active":{"type":"boolean"},"priority":{"type":"integer"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}}}},"meta":{"type":"object","properties":{"total":{"type":"integer"},"active":{"type":"integer"},"rule_types_available":{"type":"array","items":{"type":"string"}}}}}},"CreateBookingRuleRequest":{"type":"object","required":["rule_type","rule_config"],"properties":{"rule_type":{"type":"string","enum":["minimum_notice","maximum_advance","meeting_types","time_restrictions","customer_limits","buffer_override","approval_required"],"description":"Type af booking regel"},"rule_config":{"type":"object","description":"Regel konfiguration (struktur afhænger af rule_type)","example":{"minimum_hours":24,"business_hours_only":true,"allowed_days":[1,2,3,4,5]}},"is_active":{"type":"boolean","default":true},"priority":{"type":"integer","minimum":1,"maximum":100,"default":50,"description":"Regel prioritet (højere nummer = højere prioritet)"}}},"BookingRuleResponse":{"type":"object","properties":{"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"agent_id":{"type":"string","format":"uuid"},"rule_type":{"type":"string"},"rule_config":{"type":"object"},"is_active":{"type":"boolean"},"priority":{"type":"integer"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}}}}},"KnowledgeBaseResponse":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"agent_id":{"type":"string","format":"uuid"},"title":{"type":"string"},"content":{"type":"string"},"data_type":{"type":"string","enum":["product","service","faq","policy","manual"]},"tags":{"type":"array","items":{"type":"string"}},"is_active":{"type":"boolean"},"embedding_status":{"type":"string","enum":["pending","completed","failed"]},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}}}},"meta":{"type":"object","properties":{"total":{"type":"integer"},"by_type":{"type":"object","properties":{"product":{"type":"integer"},"service":{"type":"integer"},"faq":{"type":"integer"},"policy":{"type":"integer"},"manual":{"type":"integer"}}}}}}},"UploadKnowledgeRequest":{"type":"object","required":["items"],"properties":{"items":{"type":"array","maxItems":100,"items":{"type":"object","required":["title","content","data_type"],"properties":{"title":{"type":"string","minLength":1,"maxLength":200,"description":"Knowledge item titel"},"content":{"type":"string","minLength":10,"maxLength":10000,"description":"Knowledge item indhold"},"data_type":{"type":"string","enum":["product","service","faq","policy","manual"],"description":"Type af knowledge data"},"tags":{"type":"array","items":{"type":"string"},"maxItems":10,"description":"Tags til kategorisering"},"metadata":{"type":"object","description":"Ekstra metadata (valgfri)"}}}},"generate_embeddings":{"type":"boolean","default":true,"description":"Generer AI embeddings for søgning"}}},"KnowledgeUploadResponse":{"type":"object","properties":{"success":{"type":"boolean"},"message":{"type":"string"},"data":{"type":"object","properties":{"uploaded_count":{"type":"integer"},"failed_count":{"type":"integer"},"generated_embeddings":{"type":"integer"},"processing_time":{"type":"number","description":"Millisekunder"},"uploaded_items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"title":{"type":"string"},"status":{"type":"string","enum":["success","failed"]}}}},"failed_items":{"type":"array","items":{"type":"object","properties":{"title":{"type":"string"},"error":{"type":"string"}}}}}}}},"DeleteKnowledgeResponse":{"type":"object","properties":{"success":{"type":"boolean"},"message":{"type":"string"},"data":{"type":"object","properties":{"deleted_count":{"type":"integer"},"failed_count":{"type":"integer"},"deleted_items":{"type":"array","items":{"type":"string","format":"uuid"}},"failed_items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"error":{"type":"string"}}}}}}}},"StructuredDataResponse":{"type":"object","properties":{"data":{"type":"object","properties":{"company_info":{"type":"object","properties":{"name":{"type":"string"},"description":{"type":"string"},"website":{"type":"string"},"industry":{"type":"string"},"contact_info":{"type":"object","properties":{"phone":{"type":"string"},"email":{"type":"string"},"address":{"type":"string"}}}}},"services":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"description":{"type":"string"},"price":{"type":"number","nullable":true},"duration":{"type":"string","nullable":true},"availability":{"type":"string","nullable":true}}}},"communication_style":{"type":"object","properties":{"tone":{"type":"string"},"formality_level":{"type":"string"},"language_preferences":{"type":"array","items":{"type":"string"}},"response_templates":{"type":"object","properties":{"greeting":{"type":"string"},"closing":{"type":"string"},"booking_confirmation":{"type":"string"}}}}},"business_rules":{"type":"object","properties":{"booking_policies":{"type":"array","items":{"type":"string"}},"cancellation_policy":{"type":"string"},"payment_terms":{"type":"string"},"service_areas":{"type":"array","items":{"type":"string"}}}},"last_synced_at":{"type":"string","format":"date-time"}}}}},"UpdateStructuredDataRequest":{"type":"object","properties":{"company_info":{"type":"object","properties":{"name":{"type":"string"},"description":{"type":"string"},"website":{"type":"string","format":"url"},"industry":{"type":"string"},"contact_info":{"type":"object","properties":{"phone":{"type":"string"},"email":{"type":"string","format":"email"},"address":{"type":"string"}}}}},"services":{"type":"array","items":{"type":"object","required":["name"],"properties":{"name":{"type":"string"},"description":{"type":"string"},"price":{"type":"number","minimum":0},"duration":{"type":"string"},"availability":{"type":"string"}}}},"communication_style":{"type":"object","properties":{"tone":{"type":"string","enum":["professional","casual","formal","friendly"]},"formality_level":{"type":"string","enum":["very_formal","formal","neutral","casual"]},"language_preferences":{"type":"array","items":{"type":"string","enum":["danish","english","german","swedish"]}},"response_templates":{"type":"object","properties":{"greeting":{"type":"string"},"closing":{"type":"string"},"booking_confirmation":{"type":"string"}}}}},"business_rules":{"type":"object","properties":{"booking_policies":{"type":"array","items":{"type":"string"}},"cancellation_policy":{"type":"string"},"payment_terms":{"type":"string"},"service_areas":{"type":"array","items":{"type":"string"}}}},"auto_sync_knowledge":{"type":"boolean","default":true,"description":"Automatisk sync til knowledge base"}}},"ErrorResponse":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"string","description":"Error besked"},"code":{"type":"string","description":"Error kode"},"details":{"type":"object","description":"Ekstra fejl detaljer"}}},"ApiKey":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string","description":"API key navn"},"key_prefix":{"type":"string","example":"agently_live_"},"masked_key":{"type":"string","example":"agently_live_..."},"scopes":{"type":"array","items":{"type":"string","enum":["read","write","delete","admin"]}},"tier":{"type":"string","enum":["basic","pro","enterprise"]},"rate_limit_per_hour":{"type":"integer"},"rate_limit_per_day":{"type":"integer"},"last_used_at":{"type":"string","format":"date-time","nullable":true},"expires_at":{"type":"string","format":"date-time","nullable":true},"is_active":{"type":"boolean"},"created_at":{"type":"string","format":"date-time"}}},"ApiKeysResponse":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ApiKey"}},"meta":{"type":"object","properties":{"total":{"type":"integer"},"version":{"type":"string"}}}}},"ApiKeyResponse":{"type":"object","properties":{"data":{"allOf":[{"$ref":"#/components/schemas/ApiKey"},{"type":"object","properties":{"key":{"type":"string","description":"Full API key (kun vist ved oprettelse!)","example":"agently_live_abc123..."}}}]},"meta":{"type":"object","properties":{"version":{"type":"string"},"warning":{"type":"string"}}}}},"CreateApiKeyRequest":{"type":"object","required":["name"],"properties":{"name":{"type":"string","description":"API key navn","example":"Production Integration"},"scopes":{"type":"array","items":{"type":"string","enum":["read","write","delete","admin"]},"default":["read"],"description":"API key permissions"},"expires_in_days":{"type":"integer","minimum":1,"maximum":365,"description":"Udløber efter X dage (valgfri)","example":90}}},"Webhook":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string","description":"Webhook navn","example":"Production Notifications"},"url":{"type":"string","format":"url","example":"https://your-app.com/webhook/agently"},"events":{"type":"array","items":{"type":"string","enum":["api.request","api.error","rate_limit.exceeded","usage.threshold","key.created","key.deleted","booking.created","booking.confirmed","booking.cancelled","booking.rescheduled","booking.auto_confirmed","booking.requires_manual_confirmation","calendar.availability_updated","calendar.blackout_added","calendar.conflict_detected","agent.created","agent.updated","agent.activated","agent.deactivated","agent.deleted","agent.knowledge_updated","agent.auto_booking_enabled","agent.auto_booking_disabled","agent.availability_updated","conversation.started","conversation.resolved","conversation.manual_takeover","conversation.ai_resumed","conversation.escalated","conversation.archived","conversation.reactivated","email.received","email.sent","email.filtered","email.processing_failed","email.provider_connected","email.provider_disconnected","satisfaction.survey_requested","satisfaction.rating_submitted","satisfaction.rating_updated","satisfaction.feedback_received","satisfaction.low_rating_alert","system.maintenance_start","system.maintenance_end","performance.response_time_degraded","performance.response_time_recovered","quota.limit_approaching","quota.limit_exceeded"]},"description":"Events der trigger webhook - omfatter booking, samtale, email og system events"},"is_active":{"type":"boolean"},"retry_count":{"type":"integer","minimum":0,"maximum":10,"example":3},"timeout_seconds":{"type":"integer","minimum":5,"maximum":300,"example":30},"last_triggered_at":{"type":"string","format":"date-time","nullable":true},"last_success_at":{"type":"string","format":"date-time","nullable":true},"last_error_at":{"type":"string","format":"date-time","nullable":true},"last_error_message":{"type":"string","nullable":true},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}}},"WebhooksResponse":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Webhook"}},"meta":{"type":"object","properties":{"total":{"type":"integer"},"available_events":{"type":"array","items":{"type":"string"},"description":"Liste af alle tilgængelige webhook events"},"version":{"type":"string"}}}}},"WebhookResponse":{"type":"object","properties":{"data":{"allOf":[{"$ref":"#/components/schemas/Webhook"},{"type":"object","properties":{"secret":{"type":"string","description":"Webhook secret til HMAC verification (kun vist ved oprettelse!)","example":"whsec_abc123def456..."}}}]},"meta":{"type":"object","properties":{"version":{"type":"string"},"warning":{"type":"string","example":"Save the webhook secret securely. It will not be shown again and is required for signature verification."}}}}},"CreateWebhookRequest":{"type":"object","required":["name","url","events"],"properties":{"name":{"type":"string","minLength":1,"maxLength":100,"description":"Webhook navn","example":"Production Notifications"},"url":{"type":"string","format":"url","description":"HTTPS URL hvor webhook events sendes til","example":"https://your-app.com/webhook/agently"},"events":{"type":"array","items":{"type":"string","enum":["api.request","api.error","rate_limit.exceeded","usage.threshold","key.created","key.deleted","booking.created","booking.confirmed","booking.cancelled","booking.rescheduled","booking.auto_confirmed","booking.requires_manual_confirmation","calendar.availability_updated","calendar.blackout_added","calendar.conflict_detected","agent.created","agent.updated","agent.activated","agent.deactivated","agent.deleted","agent.knowledge_updated","agent.auto_booking_enabled","agent.auto_booking_disabled","agent.availability_updated","conversation.started","conversation.resolved","conversation.manual_takeover","conversation.ai_resumed","conversation.escalated","conversation.archived","conversation.reactivated","email.received","email.sent","email.filtered","email.processing_failed","email.provider_connected","email.provider_disconnected","satisfaction.survey_requested","satisfaction.rating_submitted","satisfaction.rating_updated","satisfaction.feedback_received","satisfaction.low_rating_alert","system.maintenance_start","system.maintenance_end","performance.response_time_degraded","performance.response_time_recovered","quota.limit_approaching","quota.limit_exceeded"]},"minItems":1,"description":"Events der skal trigger webhook","example":["booking.created","booking.confirmed","conversation.manual_takeover","satisfaction.low_rating_alert"]},"retry_count":{"type":"integer","minimum":0,"maximum":10,"default":3,"description":"Antal gange webhook forsøges ved fejl","example":3},"timeout_seconds":{"type":"integer","minimum":5,"maximum":300,"default":30,"description":"Max tid til at vente på svar","example":30},"headers":{"type":"object","additionalProperties":{"type":"string"},"description":"Custom headers til webhook requests (valgfri)","example":{"Authorization":"Bearer your-token"}}}},"GmailWebhookPayload":{"type":"object","properties":{"event":{"type":"string","enum":["gmail.webhook_received","gmail.history_sync_completed","gmail.authentication_failed","gmail.quota_exceeded","gmail.connection_restored"],"description":"Gmail integration webhook event type"},"timestamp":{"type":"string","format":"date-time"},"data":{"type":"object","properties":{"user_id":{"type":"string","format":"uuid"},"email_address":{"type":"string","format":"email"},"history_id":{"type":"string","description":"Gmail history ID for sync operations"},"message_count":{"type":"integer","description":"Number of messages processed"},"error_details":{"type":"object","nullable":true,"properties":{"error_code":{"type":"string"},"error_message":{"type":"string"},"retry_count":{"type":"integer"}}}}}},"example":{"event":"gmail.history_sync_completed","timestamp":"2024-08-15T10:30:00Z","data":{"user_id":"123e4567-e89b-12d3-a456-426614174000","email_address":"user@company.com","history_id":"12345678","message_count":5}}},"PerformanceAlertWebhookPayload":{"type":"object","properties":{"event":{"type":"string","enum":["performance.alert_triggered","performance.alert_resolved","performance.threshold_updated"],"description":"Performance alert webhook event type"},"timestamp":{"type":"string","format":"date-time"},"data":{"type":"object","properties":{"alert_id":{"type":"string","format":"uuid"},"agent_id":{"type":"string","format":"uuid"},"agent_name":{"type":"string"},"alert_type":{"type":"string","enum":["response_time_high","error_rate_high","satisfaction_low","volume_anomaly"]},"severity":{"type":"string","enum":["low","medium","high","critical"]},"threshold_value":{"type":"number"},"current_value":{"type":"number"},"duration_minutes":{"type":"integer"},"notification_channels":{"type":"array","items":{"type":"string","enum":["email","sms","webhook","dashboard"]}}}}},"example":{"event":"performance.alert_triggered","timestamp":"2024-08-15T10:35:00Z","data":{"alert_id":"550e8400-e29b-41d4-a716-446655440000","agent_id":"123e4567-e89b-12d3-a456-426614174000","agent_name":"Emma","alert_type":"response_time_high","severity":"high","threshold_value":10,"current_value":15.2,"duration_minutes":30,"notification_channels":["email","webhook"]}}},"AgentUnavailabilityWebhookPayload":{"type":"object","properties":{"event":{"type":"string","enum":["agent.unavailable_period_created","agent.vacation_started","agent.vacation_ended","agent.schedule_conflict_detected"],"description":"Agent unavailability webhook event type"},"timestamp":{"type":"string","format":"date-time"},"data":{"type":"object","properties":{"agent_id":{"type":"string","format":"uuid"},"agent_name":{"type":"string"},"unavailable_period_id":{"type":"string","format":"uuid"},"unavailable_type":{"type":"string","enum":["vacation","sick_leave","training","meeting","maintenance","custom"]},"start_date":{"type":"string","format":"date-time"},"end_date":{"type":"string","format":"date-time"},"reason":{"type":"string","nullable":true},"is_recurring":{"type":"boolean"},"recurrence_pattern":{"type":"object","nullable":true,"properties":{"frequency":{"type":"string","enum":["daily","weekly","monthly"]},"interval":{"type":"integer"},"days_of_week":{"type":"array","items":{"type":"integer","minimum":0,"maximum":6}}}},"affected_bookings":{"type":"array","items":{"type":"object","properties":{"booking_id":{"type":"string","format":"uuid"},"customer_email":{"type":"string","format":"email"},"scheduled_start":{"type":"string","format":"date-time"}}}}}}},"example":{"event":"agent.vacation_started","timestamp":"2024-08-15T00:00:00Z","data":{"agent_id":"123e4567-e89b-12d3-a456-426614174000","agent_name":"Emma","unavailable_period_id":"550e8400-e29b-41d4-a716-446655440000","unavailable_type":"vacation","start_date":"2024-08-15T00:00:00Z","end_date":"2024-08-22T23:59:59Z","reason":"Summer vacation","is_recurring":false,"affected_bookings":[{"booking_id":"660e8400-e29b-41d4-a716-446655440001","customer_email":"customer@example.com","scheduled_start":"2024-08-16T14:00:00Z"}]}}},"Booking":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Unique booking identifier"},"agent_id":{"type":"string","format":"uuid","description":"AI agent handling this booking"},"customer_email":{"type":"string","format":"email","description":"Customer email address"},"customer_name":{"type":"string","description":"Customer navn","example":"John Doe"},"meeting_title":{"type":"string","description":"Møde titel","example":"Product demo meeting"},"meeting_description":{"type":"string","description":"Møde beskrivelse","nullable":true},"scheduled_start":{"type":"string","format":"date-time","description":"Møde start tidspunkt (ISO 8601)"},"scheduled_end":{"type":"string","format":"date-time","description":"Møde slut tidspunkt (ISO 8601)"},"status":{"type":"string","enum":["scheduled","confirmed","cancelled","completed"],"description":"Booking status"},"booking_source":{"type":"string","enum":["manual","api","ai_agent","email_integration"],"description":"Hvordan booking blev oprettet"},"ai_confidence":{"type":"number","minimum":0,"maximum":1,"description":"AI confidence score (0-1) for booking korrekthed","example":0.87},"confirmation_sent":{"type":"boolean","description":"Om bekræftelse email er sendt"},"auto_booked":{"type":"boolean","description":"Om booking var automatisk oprettet"},"location":{"type":"string","description":"Møde lokation","nullable":true},"agent_name":{"type":"string","description":"Agent navn fra relation","example":"Emma"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}}},"CreateBookingRequest":{"type":"object","required":["agent_id","customer_email","meeting_title","scheduled_start","scheduled_end"],"properties":{"agent_id":{"type":"string","format":"uuid","description":"AI agent der skal håndtere bookingen"},"customer_email":{"type":"string","format":"email","description":"Customer email"},"customer_name":{"type":"string","description":"Customer navn (valgfri)","example":"John Doe"},"meeting_title":{"type":"string","description":"Møde titel","example":"Product demo meeting"},"meeting_description":{"type":"string","description":"Møde beskrivelse (valgfri)"},"scheduled_start":{"type":"string","format":"date-time","description":"Møde start tidspunkt (ISO 8601)","example":"2024-08-27T14:00:00Z"},"scheduled_end":{"type":"string","format":"date-time","description":"Møde slut tidspunkt (ISO 8601)","example":"2024-08-27T15:00:00Z"},"booking_source":{"type":"string","enum":["manual","api","ai_agent","email_integration"],"default":"api","description":"Kilde for booking oprettelse"},"ai_confidence":{"type":"number","minimum":0,"maximum":1,"description":"AI confidence score hvis booking kommer fra AI analyse","example":0.87},"location":{"type":"string","description":"Møde lokation (valgfri)"}}},"BookingsResponse":{"type":"object","properties":{"bookings":{"type":"array","items":{"$ref":"#/components/schemas/Booking"}},"total":{"type":"integer","description":"Antal bookings returneret"}}},"BookingCreatedResponse":{"type":"object","properties":{"booking":{"$ref":"#/components/schemas/Booking"},"message":{"type":"string","example":"Booking auto-confirmed for John Doe (AI confidence: 87%)"},"auto_confirmed":{"type":"boolean","description":"Om booking blev auto-confirmed"},"ai_confidence":{"type":"number","minimum":0,"maximum":1},"requires_manual_confirmation":{"type":"boolean","description":"Om booking kræver manuel konfirmation"}}},"CalendarEvent":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"type":{"type":"string","enum":["booking","availability","unavailable","vacation"],"description":"Event type"},"start":{"type":"string","format":"date-time"},"end":{"type":"string","format":"date-time"},"title":{"type":"string"},"description":{"type":"string","nullable":true},"agent_id":{"type":"string","format":"uuid","nullable":true},"agent_name":{"type":"string","nullable":true},"agent_color":{"type":"string","nullable":true,"example":"#3B82F6"},"agent_avatar_id":{"type":"integer","nullable":true,"minimum":1,"maximum":16},"status":{"type":"string","nullable":true},"customer_email":{"type":"string","format":"email","nullable":true},"customer_name":{"type":"string","nullable":true},"ai_confidence":{"type":"number","minimum":0,"maximum":1,"nullable":true}}},"CalendarEventsResponse":{"type":"object","properties":{"events":{"type":"array","items":{"$ref":"#/components/schemas/CalendarEvent"}},"availability":{"type":"array","items":{"type":"object","properties":{"agent_id":{"type":"string","format":"uuid"},"day_of_week":{"type":"integer","minimum":1,"maximum":7},"start_time":{"type":"string","example":"09:00"},"end_time":{"type":"string","example":"17:00"},"is_active":{"type":"boolean"}}}},"slotAvailability":{"type":"object","description":"Time slot availability lookup table","additionalProperties":{"type":"boolean"}},"agents":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"color":{"type":"string","example":"#3B82F6"},"avatar_id":{"type":"integer","minimum":1,"maximum":16}}}},"meta":{"type":"object","properties":{"start_date":{"type":"string","format":"date"},"end_date":{"type":"string","format":"date"},"total_events":{"type":"integer"}}}}},"AIBookingRequest":{"type":"object","required":["emailContent","customerEmail","agentId"],"properties":{"emailContent":{"type":"string","description":"Email indhold til AI analyse","example":"Hej, jeg vil gerne book en tid i morgen kl 14 til møde om produktdemo. Mvh John"},"customerEmail":{"type":"string","format":"email","description":"Customer email adresse"},"agentId":{"type":"string","format":"uuid","description":"AI agent der skal analysere forespørgslen"},"action":{"type":"string","enum":["analyze","autobook","confirm"],"default":"analyze","description":"Handling at udføre: analyze (kun analyse), autobook (book automatisk hvis høj confidence), confirm (bekræft specifik slot)"},"slotStart":{"type":"string","format":"date-time","description":"Specifik slot start tidspunkt (kun for confirm action)"},"slotEnd":{"type":"string","format":"date-time","description":"Specifik slot slut tidspunkt (kun for confirm action)"}}},"AIBookingResponse":{"type":"object","properties":{"success":{"type":"boolean"},"isBooking":{"type":"boolean","description":"Om email indhold blev detekteret som booking request"},"hasWeekRequest":{"type":"boolean","description":"Om forespørgslen indeholder uge nummer"},"weekNumber":{"type":"integer","nullable":true},"dateRange":{"type":"object","nullable":true,"properties":{"start":{"type":"string","format":"date"},"end":{"type":"string","format":"date"}}},"bookingRequest":{"type":"object","nullable":true,"properties":{"requestedDateTime":{"type":"object","properties":{"date":{"type":"string","format":"date-time"},"duration":{"type":"integer","description":"Møde varighed i minutter"}}},"confidence":{"type":"number","minimum":0,"maximum":1},"extractedInfo":{"type":"object","properties":{"purpose":{"type":"string"},"preferredTime":{"type":"string","nullable":true},"duration":{"type":"integer","nullable":true}}}}},"availabilityCheck":{"type":"object","nullable":true,"properties":{"isAvailable":{"type":"boolean"},"conflicts":{"type":"array","items":{"type":"string"}}}},"suggestedSlots":{"type":"array","items":{"type":"object","properties":{"start":{"type":"string","format":"date-time"},"end":{"type":"string","format":"date-time"},"available":{"type":"boolean"}}}},"autoBookSlot":{"type":"object","nullable":true,"properties":{"start":{"type":"string","format":"date-time"},"end":{"type":"string","format":"date-time"}}},"suggestedResponse":{"type":"string","description":"AI genereret svar til kunden"},"confidence":{"type":"number","minimum":0,"maximum":1},"autoBooked":{"type":"boolean","description":"Om booking blev automatisk oprettet"},"confirmed":{"type":"boolean","description":"Om booking blev bekræftet"},"booking":{"$ref":"#/components/schemas/Booking","nullable":true},"confirmationMessage":{"type":"string","nullable":true}}},"AIBookingStatsResponse":{"type":"object","properties":{"success":{"type":"boolean"},"recentBookings":{"type":"array","items":{"$ref":"#/components/schemas/Booking"}},"stats":{"type":"object","properties":{"totalAIBookings":{"type":"integer","description":"Antal AI bookings i seneste 24 timer"},"averageConfidence":{"type":"number","minimum":0,"maximum":1,"description":"Gennemsnit AI confidence score"},"confirmedBookings":{"type":"integer","description":"Antal bekræftede bookings"},"pendingBookings":{"type":"integer","description":"Antal ventende bookings"}}}}},"AutoConfirmResponse":{"type":"object","properties":{"success":{"type":"boolean"},"processedBookings":{"type":"integer","description":"Antal bookings behandlet"},"autoConfirmedBookings":{"type":"integer","description":"Antal automatisk bekræftede bookings"},"skippedBookings":{"type":"integer","description":"Antal skippede bookings"},"results":{"type":"array","items":{"type":"object","properties":{"bookingId":{"type":"string","format":"uuid"},"action":{"type":"string","enum":["confirmed","skipped"]},"reason":{"type":"string"},"aiConfidence":{"type":"number","minimum":0,"maximum":1},"threshold":{"type":"number","minimum":0,"maximum":1}}}}}},"EmailFiltersResponse":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/EmailFilter"}},"meta":{"type":"object","properties":{"total":{"type":"integer","description":"Samlet antal filters"},"active":{"type":"integer","description":"Antal aktive filters"},"categories":{"type":"array","items":{"type":"string"},"description":"Tilgængelige filter kategorier"}}}}},"EmailFilter":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"user_id":{"type":"string","format":"uuid"},"name":{"type":"string","description":"Filter navn","example":"Spam Detector"},"category":{"type":"string","enum":["spam","phishing","marketing","custom"],"description":"Filter kategori"},"filter_config":{"type":"object","properties":{"conditions":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string","enum":["from","subject","content","domain"],"description":"Email felt at teste"},"operator":{"type":"string","enum":["contains","equals","starts_with","ends_with","regex"],"description":"Sammenligning operator"},"value":{"type":"string","description":"Værdi at teste for"},"case_sensitive":{"type":"boolean","default":false}}}},"logic":{"type":"string","enum":["AND","OR"],"default":"AND","description":"Logik for multiple conditions"},"action":{"type":"string","enum":["block","allow","flag","forward"],"description":"Handling ved match"}}},"is_active":{"type":"boolean","default":true},"confidence_threshold":{"type":"number","minimum":0,"maximum":1,"default":0.7,"description":"AI confidence minimum for automatisk handling"},"accuracy_rate":{"type":"number","minimum":0,"maximum":100,"description":"Filter accuracy percentage baseret på feedback"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}}},"CreateEmailFilterRequest":{"type":"object","required":["name","category","filter_config"],"properties":{"name":{"type":"string","minLength":1,"maxLength":100,"description":"Filter navn","example":"Marketing Email Blocker"},"category":{"type":"string","enum":["spam","phishing","marketing","custom"],"description":"Filter kategori"},"filter_config":{"type":"object","required":["conditions","action"],"properties":{"conditions":{"type":"array","minItems":1,"items":{"type":"object","required":["field","operator","value"],"properties":{"field":{"type":"string","enum":["from","subject","content","domain"]},"operator":{"type":"string","enum":["contains","equals","starts_with","ends_with","regex"]},"value":{"type":"string","minLength":1},"case_sensitive":{"type":"boolean","default":false}}}},"logic":{"type":"string","enum":["AND","OR"],"default":"AND"},"action":{"type":"string","enum":["block","allow","flag","forward"]}}},"confidence_threshold":{"type":"number","minimum":0.1,"maximum":1,"default":0.7},"is_active":{"type":"boolean","default":true}}},"UpdateEmailFilterRequest":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":100},"category":{"type":"string","enum":["spam","phishing","marketing","custom"]},"filter_config":{"type":"object","properties":{"conditions":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string","enum":["from","subject","content","domain"]},"operator":{"type":"string","enum":["contains","equals","starts_with","ends_with","regex"]},"value":{"type":"string"},"case_sensitive":{"type":"boolean"}}}},"logic":{"type":"string","enum":["AND","OR"]},"action":{"type":"string","enum":["block","allow","flag","forward"]}}},"confidence_threshold":{"type":"number","minimum":0.1,"maximum":1},"is_active":{"type":"boolean"}}},"EmailFilterResponse":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/EmailFilter"},"meta":{"type":"object","properties":{"performance":{"type":"object","properties":{"total_processed":{"type":"integer","description":"Antal emails processeret"},"accuracy_rate":{"type":"number","description":"Nøjagtighed procent"},"false_positives":{"type":"integer"},"false_negatives":{"type":"integer"}}},"version":{"type":"string"}}}}},"TestEmailFilterRequest":{"type":"object","required":["email"],"properties":{"email":{"type":"object","required":["from","subject"],"properties":{"from":{"type":"string","format":"email","description":"Afsender email adresse","example":"test@marketing.com"},"subject":{"type":"string","description":"Email emne","example":"Special Offer - 50% Off!"},"content":{"type":"string","description":"Email indhold (valgfrit)","example":"Limited time offer - click here to save!"}}}}},"EmailFilterTestResponse":{"type":"object","properties":{"result":{"type":"object","properties":{"action":{"type":"string","enum":["block","allow","flag","forward"],"description":"Anbefalede handling"},"matched_filters":{"type":"array","items":{"type":"object","properties":{"filter_id":{"type":"string","format":"uuid"},"filter_name":{"type":"string"},"confidence":{"type":"number","minimum":0,"maximum":1},"matched_conditions":{"type":"array","items":{"type":"string"}}}}},"overall_confidence":{"type":"number","minimum":0,"maximum":1,"description":"Samlet confidence score"},"explanation":{"type":"string","description":"Forklaring på beslutningen"}}}}},"EmailFilterStatsResponse":{"type":"object","properties":{"total":{"type":"integer","description":"Samlet antal emails processeret"},"blocked":{"type":"integer","description":"Antal blokerede emails"},"allowed":{"type":"integer","description":"Antal tilladte emails"},"accuracy":{"type":"number","minimum":0,"maximum":100,"description":"Filter nøjagtighed i procent"},"recentActions":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"email_from":{"type":"string"},"email_subject":{"type":"string"},"action_taken":{"type":"string","enum":["block","allow","flag","forward"]},"reason":{"type":"string","description":"Filter match grund"},"was_correct":{"type":"boolean","nullable":true,"description":"Bruger feedback på nøjagtighed"},"created_at":{"type":"string","format":"date-time"}}}}}},"AutoLearningInsightsResponse":{"type":"object","properties":{"insights":{"type":"object","properties":{"patterns_discovered":{"type":"array","items":{"type":"object","properties":{"pattern_type":{"type":"string","enum":["sender_pattern","subject_pattern","content_pattern","domain_pattern"]},"pattern_value":{"type":"string"},"confidence":{"type":"number","minimum":0,"maximum":1},"occurrences":{"type":"integer"},"accuracy":{"type":"number"}}}},"recommendations":{"type":"array","items":{"type":"object","properties":{"action":{"type":"string","enum":["create_filter","update_filter","merge_filters","remove_filter"]},"description":{"type":"string"},"confidence":{"type":"number"},"impact":{"type":"string","enum":["low","medium","high"],"description":"Forventet impact på performance"}}}},"learning_progress":{"type":"object","properties":{"emails_processed":{"type":"integer"},"feedback_received":{"type":"integer"},"accuracy_improvement":{"type":"number","description":"Forbedring siden sidste læringsperiode"}}}}}}},"AutoLearningResultResponse":{"type":"object","properties":{"message":{"type":"string","description":"Resultat besked"},"patterns":{"type":"array","items":{"type":"object","properties":{"pattern":{"type":"string"},"confidence":{"type":"number"},"occurrences":{"type":"integer"}}}},"filtersCreated":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"category":{"type":"string"},"confidence_threshold":{"type":"number"}}}}}},"PendingEmailsResponse":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"email_from":{"type":"string"},"email_subject":{"type":"string"},"email_content":{"type":"string"},"received_at":{"type":"string","format":"date-time"},"reason":{"type":"string","description":"Hvorfor afventer det review"},"suggested_action":{"type":"string","enum":["block","allow","flag","forward"]},"confidence":{"type":"number","minimum":0,"maximum":1}}}},"meta":{"type":"object","properties":{"total":{"type":"integer"},"pending_time_avg":{"type":"integer","description":"Gennemsnit ventetid i timer"}}}}},"FilterFeedbackRequest":{"type":"object","required":["actionId","wasCorrect"],"properties":{"actionId":{"type":"string","format":"uuid","description":"ID på filter handling at give feedback på"},"wasCorrect":{"type":"boolean","description":"Om filter beslutningen var korrekt"},"comment":{"type":"string","maxLength":500,"description":"Valgfri kommentar til feedbacken"}}},"StopAskingRequest":{"type":"object","required":["scope"],"properties":{"scope":{"type":"string","enum":["all","sender","domain","category"],"description":"Omfang af stop asking request"},"value":{"type":"string","description":"Specific værdi for scope (email, domain, etc.)"},"reason":{"type":"string","maxLength":200,"description":"Grund til at stoppe prompts"}}},"CleanupResultResponse":{"type":"object","properties":{"duplicatesFound":{"type":"integer","description":"Antal duplicate filters fundet"},"duplicatesRemoved":{"type":"integer","description":"Antal duplicate filters fjernet"},"redundantFilters":{"type":"array","items":{"type":"object","properties":{"filterId":{"type":"string","format":"uuid"},"filterName":{"type":"string"},"reason":{"type":"string","description":"Hvorfor det er redundant"}}}},"performanceImprovement":{"type":"string","description":"Estimeret performance forbedring"}}},"UnblockEmailRequest":{"type":"object","required":["email"],"properties":{"email":{"type":"string","format":"email","description":"Email adresse at unblokke","example":"unblock@example.com"},"reason":{"type":"string","maxLength":200,"description":"Grund til at unblokke adressen"},"create_whitelist_rule":{"type":"boolean","default":false,"description":"Opret automatisk whitelist regel"}}},"SuccessResponse":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","description":"Success besked"}}},"Error":{"type":"object","properties":{"error":{"type":"string","description":"Error type"},"message":{"type":"string","description":"Detaljeret fejlbesked"}}},"ToggleConversationModeRequest":{"type":"object","required":["conversationId","enableManualMode"],"properties":{"conversationId":{"type":"string","format":"uuid","description":"Samtale ID der skal ændres","example":"123e4567-e89b-12d3-a456-426614174000"},"enableManualMode":{"type":"boolean","description":"true = manuel håndtering, false = AI automatisk","example":true}}},"AgentConversationsResponse":{"type":"object","properties":{"conversations":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"customer_email":{"type":"string","format":"email"},"subject":{"type":"string"},"status":{"type":"string","enum":["active","resolved","escalated"]},"is_manual_mode":{"type":"boolean"},"message_count":{"type":"integer","minimum":0},"last_message_at":{"type":"string","format":"date-time"},"created_at":{"type":"string","format":"date-time"},"thread_id":{"type":"string","nullable":true},"priority":{"type":"string","enum":["low","normal","high","urgent"],"default":"normal"}}}},"pagination":{"type":"object","properties":{"total":{"type":"integer"},"limit":{"type":"integer"},"offset":{"type":"integer"},"has_more":{"type":"boolean"}}},"stats":{"type":"object","properties":{"total_conversations":{"type":"integer"},"active_conversations":{"type":"integer"},"resolved_conversations":{"type":"integer"},"escalated_conversations":{"type":"integer"}}}}},"GmailWebhookVerificationRequest":{"type":"object","required":["token"],"properties":{"token":{"type":"string","description":"Verifikations token fra Google Cloud Pub/Sub","example":"verification-token-123"}}},"EmailPollingResultResponse":{"type":"object","properties":{"success":{"type":"boolean"},"results":{"type":"array","items":{"type":"object","properties":{"user_id":{"type":"string","format":"uuid"},"emails_processed":{"type":"integer","minimum":0},"new_conversations":{"type":"integer","minimum":0},"ai_responses_sent":{"type":"integer","minimum":0},"errors":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string"},"message":{"type":"string"},"timestamp":{"type":"string","format":"date-time"}}}},"provider_status":{"type":"object","properties":{"gmail":{"type":"object","properties":{"connected":{"type":"boolean"},"quota_remaining":{"type":"integer"},"last_sync":{"type":"string","format":"date-time"}}}}}}}},"total_users_processed":{"type":"integer"},"total_emails_processed":{"type":"integer"},"execution_time_ms":{"type":"integer"},"timestamp":{"type":"string","format":"date-time"}}},"TriggerPollingRequest":{"type":"object","properties":{"userId":{"type":"string","format":"uuid","description":"Specifik bruger ID til polling (valgfrit)"},"pollAll":{"type":"boolean","default":false,"description":"Poll alle brugere (kræver admin rettigheder)"},"forceSync":{"type":"boolean","default":false,"description":"Tving fuld sync uanset sidst sync tidspunkt"}}},"TestEmailPollingRequest":{"type":"object","required":["userId"],"properties":{"userId":{"type":"string","format":"uuid","description":"Bruger ID at teste email polling for","example":"123e4567-e89b-12d3-a456-426614174000"},"limit":{"type":"integer","minimum":1,"maximum":50,"default":10,"description":"Antal emails at hente til test"}}},"TestEmailPollingResponse":{"type":"object","properties":{"user_id":{"type":"string","format":"uuid"},"providers_tested":{"type":"array","items":{"type":"object","properties":{"provider":{"type":"string","enum":["gmail"]},"connected":{"type":"boolean"},"status":{"type":"string"},"error":{"type":"string","nullable":true},"emails_found":{"type":"integer","minimum":0},"quota_info":{"type":"object","properties":{"remaining":{"type":"integer"},"limit":{"type":"integer"},"reset_time":{"type":"string","format":"date-time"}}}}}},"sample_emails":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"from":{"type":"string","format":"email"},"subject":{"type":"string"},"received_at":{"type":"string","format":"date-time"},"thread_id":{"type":"string","nullable":true},"has_attachments":{"type":"boolean"}}}},"test_timestamp":{"type":"string","format":"date-time"}}},"GmailAccountsResponse":{"type":"object","properties":{"success":{"type":"boolean","example":true},"accounts":{"type":"array","items":{"$ref":"#/components/schemas/GmailAccountResponse"}},"total":{"type":"integer","description":"Samlet antal Gmail accounts","example":3},"active":{"type":"integer","description":"Antal aktive accounts","example":2}}},"AddGmailAccountRequest":{"type":"object","required":["email"],"properties":{"email":{"type":"string","format":"email","description":"Gmail email adresse","example":"agent@company.dk"},"oauth_code":{"type":"string","description":"OAuth authorization code fra Google (if using OAuth flow)","example":"4/0AY0e-g7..."},"display_name":{"type":"string","description":"Synlig navn for denne Gmail account","example":"Company Support"},"sync_enabled":{"type":"boolean","default":true,"description":"Enable automatic email sync"},"agent_assignments":{"type":"array","items":{"type":"string","format":"uuid"},"description":"AI agent IDs der skal håndtere emails fra denne account"}}},"GmailAccountResponse":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"email":{"type":"string","format":"email"},"display_name":{"type":"string"},"is_active":{"type":"boolean"},"sync_enabled":{"type":"boolean"},"connection_status":{"type":"string","enum":["connected","disconnected","expired","error"]},"last_sync_at":{"type":"string","format":"date-time","nullable":true},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}}},"GmailAccountDetailsResponse":{"type":"object","allOf":[{"$ref":"#/components/schemas/GmailAccountResponse"},{"type":"object","properties":{"sync_metrics":{"type":"object","properties":{"emails_processed_today":{"type":"integer"},"emails_processed_total":{"type":"integer"},"last_error":{"type":"string","nullable":true},"last_error_at":{"type":"string","format":"date-time","nullable":true},"quota_usage":{"type":"object","properties":{"daily_quota_used":{"type":"integer"},"daily_quota_limit":{"type":"integer"},"quota_reset_time":{"type":"string","format":"date-time"}}}}},"agent_assignments":{"type":"array","items":{"type":"object","properties":{"agent_id":{"type":"string","format":"uuid"},"agent_name":{"type":"string"},"assigned_at":{"type":"string","format":"date-time"}}}},"oauth_status":{"type":"object","properties":{"token_valid":{"type":"boolean"},"token_expires_at":{"type":"string","format":"date-time","nullable":true},"scopes_granted":{"type":"array","items":{"type":"string"}},"needs_reauth":{"type":"boolean"}}}}}]},"UpdateGmailAccountRequest":{"type":"object","properties":{"display_name":{"type":"string","description":"Opdater display navn"},"sync_enabled":{"type":"boolean","description":"Enable/disable automatic sync"},"agent_assignments":{"type":"array","items":{"type":"string","format":"uuid"},"description":"Opdater AI agent assignments"},"sync_settings":{"type":"object","properties":{"sync_interval_minutes":{"type":"integer","minimum":1,"maximum":1440,"description":"Sync interval i minutter"},"sync_labels":{"type":"array","items":{"type":"string"},"description":"Gmail labels at sync (default: INBOX)"},"auto_archive":{"type":"boolean","description":"Automatically archive processed emails"}}}}},"TokenRefreshResponse":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"Tokens refreshed successfully"},"token_info":{"type":"object","properties":{"expires_at":{"type":"string","format":"date-time"},"scopes":{"type":"array","items":{"type":"string"}},"refreshed_at":{"type":"string","format":"date-time"}}}}},"SubmitSatisfactionRequest":{"type":"object","required":["conversationId","rating"],"properties":{"conversationId":{"type":"string","format":"uuid","description":"Samtale ID for satisfaction rating","example":"123e4567-e89b-12d3-a456-426614174000"},"rating":{"type":"integer","minimum":1,"maximum":5,"description":"Kunde satisfaction rating (1-5 stjerner)","example":4},"feedback":{"type":"string","maxLength":1000,"description":"Valgfrit tekstfeedback fra kunde","example":"Hurtig og hjælpsom service!"},"customer_email":{"type":"string","format":"email","description":"Kundens email adresse (til verifikation)","example":"kunde@example.com"}}},"SatisfactionRatingResponse":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"conversation_id":{"type":"string","format":"uuid"},"rating":{"type":"integer","minimum":1,"maximum":5},"feedback":{"type":"string","nullable":true},"customer_email":{"type":"string","format":"email"},"submitted_at":{"type":"string","format":"date-time"},"ip_address":{"type":"string","nullable":true},"user_agent":{"type":"string","nullable":true},"conversation":{"type":"object","nullable":true,"properties":{"subject":{"type":"string"},"agent_name":{"type":"string"},"resolved_at":{"type":"string","format":"date-time"}}}}},"RequestSatisfactionSurveyRequest":{"type":"object","required":["conversationId"],"properties":{"conversationId":{"type":"string","format":"uuid","description":"Samtale ID for at sende satisfaction survey","example":"123e4567-e89b-12d3-a456-426614174000"},"send_immediately":{"type":"boolean","default":false,"description":"Send survey straks i stedet for efter delay"},"custom_message":{"type":"string","maxLength":500,"description":"Tilpasset besked i survey email"}}},"WebhookPayloadBase":{"type":"object","required":["event","timestamp","data"],"properties":{"event":{"type":"string","description":"Webhook event type","example":"booking.created"},"timestamp":{"type":"string","format":"date-time","description":"Event timestamp","example":"2024-01-15T10:30:00Z"},"data":{"type":"object","description":"Event-specific payload data"},"user_id":{"type":"string","format":"uuid","description":"User ID associated with event","example":"123e4567-e89b-12d3-a456-426614174000"}}},"BookingWebhookPayload":{"allOf":[{"$ref":"#/components/schemas/WebhookPayloadBase"},{"type":"object","properties":{"event":{"type":"string","enum":["booking.created","booking.confirmed","booking.cancelled","booking.rescheduled","booking.auto_confirmed","booking.requires_manual_confirmation"]},"data":{"type":"object","required":["booking_id","agent_id","customer_email"],"properties":{"booking_id":{"type":"string","format":"uuid","description":"Booking ID"},"agent_id":{"type":"string","format":"uuid","description":"AI agent ID"},"customer_email":{"type":"string","format":"email","description":"Customer email address"},"customer_name":{"type":"string","description":"Customer name"},"meeting_title":{"type":"string","description":"Meeting title"},"scheduled_start":{"type":"string","format":"date-time","description":"Meeting start time"},"scheduled_end":{"type":"string","format":"date-time","description":"Meeting end time"},"status":{"type":"string","enum":["scheduled","confirmed","cancelled"],"description":"Booking status"},"ai_confidence":{"type":"number","minimum":0,"maximum":1,"description":"AI confidence score for auto-booking"}}}}}]},"CalendarWebhookPayload":{"allOf":[{"$ref":"#/components/schemas/WebhookPayloadBase"},{"type":"object","properties":{"event":{"type":"string","enum":["calendar.availability_updated","calendar.blackout_added","calendar.conflict_detected"]},"data":{"type":"object","required":["agent_id"],"properties":{"agent_id":{"type":"string","format":"uuid","description":"AI agent ID"},"availability_slots":{"type":"array","items":{"type":"object","properties":{"day_of_week":{"type":"integer","minimum":0,"maximum":6,"description":"Day of week (0=Sunday, 6=Saturday)"},"start_time":{"type":"string","pattern":"^([01]?[0-9]|2[0-3]):[0-5][0-9]$","description":"Start time (HH:MM format)"},"end_time":{"type":"string","pattern":"^([01]?[0-9]|2[0-3]):[0-5][0-9]$","description":"End time (HH:MM format)"}}}},"blackout_period":{"type":"object","properties":{"start_date":{"type":"string","format":"date-time","description":"Blackout start"},"end_date":{"type":"string","format":"date-time","description":"Blackout end"},"reason":{"type":"string","description":"Blackout reason"}}}}}}}]},"AgentWebhookPayload":{"allOf":[{"$ref":"#/components/schemas/WebhookPayloadBase"},{"type":"object","properties":{"event":{"type":"string","enum":["agent.created","agent.updated","agent.activated","agent.deactivated","agent.deleted","agent.knowledge_updated","agent.auto_booking_enabled","agent.auto_booking_disabled","agent.availability_updated"]},"data":{"type":"object","required":["agent_id"],"properties":{"agent_id":{"type":"string","format":"uuid","description":"AI agent ID"},"agent_name":{"type":"string","description":"Agent name"},"role":{"type":"string","enum":["sales","support","general"],"description":"Agent role"},"is_active":{"type":"boolean","description":"Agent active status"},"auto_booking_enabled":{"type":"boolean","description":"Auto-booking enabled status"},"changes":{"type":"object","description":"Changed fields for update events"}}}}}]},"ConversationWebhookPayload":{"allOf":[{"$ref":"#/components/schemas/WebhookPayloadBase"},{"type":"object","properties":{"event":{"type":"string","enum":["conversation.started","conversation.resolved","conversation.manual_takeover","conversation.ai_resumed","conversation.escalated","conversation.archived","conversation.reactivated"]},"data":{"type":"object","required":["conversation_id","agent_id","customer_email"],"properties":{"conversation_id":{"type":"string","format":"uuid","description":"Conversation ID"},"agent_id":{"type":"string","format":"uuid","description":"AI agent ID"},"customer_email":{"type":"string","format":"email","description":"Customer email address"},"subject":{"type":"string","description":"Email subject/conversation topic"},"status":{"type":"string","enum":["active","resolved","escalated","archived"],"description":"Conversation status"},"is_manual_takeover":{"type":"boolean","description":"Manual takeover status"},"message_count":{"type":"integer","description":"Total messages in conversation"}}}}}]},"EmailWebhookPayload":{"allOf":[{"$ref":"#/components/schemas/WebhookPayloadBase"},{"type":"object","properties":{"event":{"type":"string","enum":["email.received","email.sent","email.filtered","email.processing_failed","email.provider_connected","email.provider_disconnected"]},"data":{"type":"object","required":["message_id","from","to"],"properties":{"message_id":{"type":"string","description":"Email message ID"},"conversation_id":{"type":"string","format":"uuid","description":"Associated conversation ID"},"agent_id":{"type":"string","format":"uuid","description":"Assigned AI agent ID"},"from":{"type":"string","format":"email","description":"Sender email address"},"to":{"type":"string","format":"email","description":"Recipient email address"},"subject":{"type":"string","description":"Email subject"},"filter_action":{"type":"string","enum":["allow","block","review"],"description":"Applied filter action"},"provider_type":{"type":"string","enum":["gmail","outlook","imap"],"description":"Email provider type"},"error_message":{"type":"string","description":"Error details for failed events"}}}}}]},"SatisfactionWebhookPayload":{"allOf":[{"$ref":"#/components/schemas/WebhookPayloadBase"},{"type":"object","properties":{"event":{"type":"string","enum":["satisfaction.survey_requested","satisfaction.rating_submitted","satisfaction.rating_updated","satisfaction.feedback_received","satisfaction.low_rating_alert"]},"data":{"type":"object","required":["conversation_id","customer_email"],"properties":{"satisfaction_id":{"type":"string","format":"uuid","description":"Satisfaction rating ID"},"conversation_id":{"type":"string","format":"uuid","description":"Associated conversation ID"},"agent_id":{"type":"string","format":"uuid","description":"AI agent ID"},"customer_email":{"type":"string","format":"email","description":"Customer email address"},"rating":{"type":"integer","minimum":1,"maximum":5,"description":"Customer rating (1-5 stars)"},"feedback":{"type":"string","description":"Customer feedback text"},"survey_sent_at":{"type":"string","format":"date-time","description":"Survey request timestamp"},"is_low_rating":{"type":"boolean","description":"Whether rating is considered low (≤2 stars)"}}}}}]},"SystemWebhookPayload":{"allOf":[{"$ref":"#/components/schemas/WebhookPayloadBase"},{"type":"object","properties":{"event":{"type":"string","enum":["system.maintenance_start","system.maintenance_end","performance.response_time_degraded","performance.response_time_recovered","quota.limit_approaching","quota.limit_exceeded"]},"data":{"type":"object","properties":{"maintenance_type":{"type":"string","enum":["scheduled","emergency","security"],"description":"Type of maintenance"},"expected_duration":{"type":"integer","description":"Expected duration in minutes"},"affected_services":{"type":"array","items":{"type":"string"},"description":"List of affected services"},"response_time_ms":{"type":"integer","description":"Current response time in milliseconds"},"threshold_ms":{"type":"integer","description":"Response time threshold in milliseconds"},"quota_type":{"type":"string","enum":["api_requests","emails_processed","storage_used"],"description":"Type of quota limit"},"current_usage":{"type":"integer","description":"Current usage amount"},"quota_limit":{"type":"integer","description":"Total quota limit"},"usage_percentage":{"type":"number","minimum":0,"maximum":100,"description":"Current usage as percentage of limit"}}}}}]},"ApiWebhookPayload":{"allOf":[{"$ref":"#/components/schemas/WebhookPayloadBase"},{"type":"object","properties":{"event":{"type":"string","enum":["api.request","api.error","rate_limit.exceeded","usage.threshold","key.created","key.deleted"]},"data":{"type":"object","properties":{"api_key_id":{"type":"string","description":"API key identifier (masked for security)"},"endpoint":{"type":"string","description":"API endpoint path"},"method":{"type":"string","enum":["GET","POST","PUT","DELETE"],"description":"HTTP method"},"status_code":{"type":"integer","description":"HTTP response status code"},"response_time_ms":{"type":"integer","description":"Request response time in milliseconds"},"error_message":{"type":"string","description":"Error details for failed requests"},"rate_limit_window":{"type":"string","description":"Rate limit time window (e.g. \"1m\", \"1h\")"},"requests_remaining":{"type":"integer","description":"Remaining requests in current window"},"reset_time":{"type":"string","format":"date-time","description":"When rate limit resets"},"key_permissions":{"type":"array","items":{"type":"string"},"description":"Permissions for created/deleted API keys"}}}}}]},"MultiAgentAvailabilityResponse":{"type":"object","properties":{"agents":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"role":{"type":"string","enum":["sales","support","followup"]},"is_active":{"type":"boolean"},"availability":{"type":"object","properties":{"available_slots":{"type":"array","items":{"type":"object","properties":{"start":{"type":"string","format":"date-time"},"end":{"type":"string","format":"date-time"},"duration_minutes":{"type":"integer","minimum":15}}}},"next_available":{"type":"string","format":"date-time","nullable":true,"description":"Næste tilgængelige tidspunkt"},"current_bookings":{"type":"integer","minimum":0},"max_concurrent":{"type":"integer","minimum":1}}},"vacation_periods":{"type":"array","items":{"$ref":"#/components/schemas/VacationPeriod"}}}}},"date_range":{"type":"object","properties":{"start_date":{"type":"string","format":"date"},"end_date":{"type":"string","format":"date"}}},"blackout_periods":{"type":"array","items":{"$ref":"#/components/schemas/SystemBlackoutPeriod"}}}},"CalendarBlackoutResponse":{"type":"object","properties":{"blackout_periods":{"type":"array","items":{"$ref":"#/components/schemas/CalendarBlackoutPeriod"}},"total":{"type":"integer","minimum":0},"pagination":{"$ref":"#/components/schemas/PaginationMeta"}}},"CreateCalendarBlackoutRequest":{"type":"object","required":["title","start_date","end_date"],"properties":{"title":{"type":"string","minLength":1,"maxLength":200,"description":"Blackout periode titel","example":"Juleferie - lukket"},"description":{"type":"string","maxLength":1000,"description":"Detaljeret beskrivelse af blackout periode","example":"Kontoret er lukket i juleperioden. Ingen bookings tilladt."},"start_date":{"type":"string","format":"date","description":"Blackout start dato","example":"2024-12-23"},"end_date":{"type":"string","format":"date","description":"Blackout slut dato","example":"2024-12-30"},"all_day":{"type":"boolean","default":true,"description":"Hele dagen eller specifikt tidspunkt"},"start_time":{"type":"string","pattern":"^([0-1][0-9]|2[0-3]):[0-5][0-9]$","description":"Start tid hvis ikke all_day","example":"09:00"},"end_time":{"type":"string","pattern":"^([0-1][0-9]|2[0-3]):[0-5][0-9]$","description":"Slut tid hvis ikke all_day","example":"17:00"},"affects_all_agents":{"type":"boolean","default":false,"description":"Om blackout påvirker alle agents eller kun specifikke"},"affected_agents":{"type":"array","items":{"type":"string","format":"uuid"},"description":"Agent IDs der påvirkes hvis ikke affects_all_agents"},"booking_redirect_message":{"type":"string","maxLength":500,"description":"Besked til kunder der prøver at booke i blackout periode","example":"Vi er lukket i juleperioden. Vælg venligst en dato efter 2. januar."}}},"CalendarBlackoutPeriod":{"allOf":[{"$ref":"#/components/schemas/CreateCalendarBlackoutRequest"},{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"user_id":{"type":"string","format":"uuid"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"},"is_active":{"type":"boolean","default":true},"booking_attempts_blocked":{"type":"integer","minimum":0,"description":"Antal booking forsøg blokeret af denne blackout"}}}]},"SystemBlackoutResponse":{"type":"object","properties":{"blackout_periods":{"type":"array","items":{"$ref":"#/components/schemas/SystemBlackoutPeriod"}},"total":{"type":"integer","minimum":0},"pagination":{"$ref":"#/components/schemas/PaginationMeta"}}},"CreateSystemBlackoutRequest":{"type":"object","required":["title","start_date","end_date","type"],"properties":{"title":{"type":"string","minLength":1,"maxLength":200,"description":"System blackout titel","example":"Planlagt vedligeholdelse"},"description":{"type":"string","maxLength":1000,"description":"Beskrivelse af system blackout","example":"Scheduled server maintenance. All booking services temporarily unavailable."},"type":{"type":"string","enum":["maintenance","holiday","emergency","custom"],"description":"Type af system blackout"},"start_date":{"type":"string","format":"date","description":"System blackout start dato","example":"2024-03-15"},"end_date":{"type":"string","format":"date","description":"System blackout slut dato","example":"2024-03-15"},"all_day":{"type":"boolean","default":false,"description":"Hele dagen eller specifikt tidspunkt"},"start_time":{"type":"string","pattern":"^([0-1][0-9]|2[0-3]):[0-5][0-9]$","description":"Start tid hvis ikke all_day","example":"02:00"},"end_time":{"type":"string","pattern":"^([0-1][0-9]|2[0-3]):[0-5][0-9]$","description":"Slut tid hvis ikke all_day","example":"06:00"},"affects_booking":{"type":"boolean","default":true,"description":"Om blackout blokerer nye bookings"},"affects_ai_responses":{"type":"boolean","default":true,"description":"Om blackout stopper AI email responses"},"affects_webhooks":{"type":"boolean","default":false,"description":"Om blackout deaktiverer webhook processing"},"maintenance_message":{"type":"string","maxLength":500,"description":"Besked vist til brugere under blackout","example":"Agently genomgår planlagt vedligeholdelse. Tjenesten er tilbage kl. 06:00."}}},"SystemBlackoutPeriod":{"allOf":[{"$ref":"#/components/schemas/CreateSystemBlackoutRequest"},{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"created_by":{"type":"string","format":"uuid"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"},"is_active":{"type":"boolean","default":true},"impact_stats":{"type":"object","properties":{"booking_requests_blocked":{"type":"integer","minimum":0},"ai_responses_delayed":{"type":"integer","minimum":0},"webhook_events_queued":{"type":"integer","minimum":0}}}}}]},"VacationPeriodsResponse":{"type":"object","properties":{"vacation_periods":{"type":"array","items":{"$ref":"#/components/schemas/VacationPeriod"}},"total":{"type":"integer","minimum":0},"pagination":{"$ref":"#/components/schemas/PaginationMeta"},"stats":{"type":"object","properties":{"active_vacations":{"type":"integer","minimum":0},"upcoming_vacations":{"type":"integer","minimum":0},"agents_on_vacation":{"type":"integer","minimum":0}}}}},"CreateVacationRequest":{"type":"object","required":["agent_id","title","start_date","end_date"],"properties":{"agent_id":{"type":"string","format":"uuid","description":"AI agent der skal have ferie"},"title":{"type":"string","minLength":1,"maxLength":200,"description":"Ferie titel","example":"Sommerferie 2024"},"description":{"type":"string","maxLength":1000,"description":"Beskrivelse af ferie periode","example":"Agent på sommerferie. Backup agent håndterer emails."},"start_date":{"type":"string","format":"date","description":"Ferie start dato","example":"2024-07-01"},"end_date":{"type":"string","format":"date","description":"Ferie slut dato","example":"2024-07-14"},"all_day":{"type":"boolean","default":true,"description":"Hele dagen eller specifikt tidspunkt"},"start_time":{"type":"string","pattern":"^([0-1][0-9]|2[0-3]):[0-5][0-9]$","description":"Start tid hvis delvis dag","example":"12:00"},"end_time":{"type":"string","pattern":"^([0-1][0-9]|2[0-3]):[0-5][0-9]$","description":"Slut tid hvis delvis dag","example":"17:00"},"backup_agent_id":{"type":"string","format":"uuid","nullable":true,"description":"Agent der tager over under ferie"},"auto_reply_enabled":{"type":"boolean","default":true,"description":"Send automatisk ferie-reply til emails"},"auto_reply_message":{"type":"string","maxLength":500,"description":"Besked i automatisk ferie-reply","example":"Tak for din henvendelse. Jeg er på ferie fra 1.-14. juli. Din besked bliver besvaret når jeg vender tilbage."},"priority":{"type":"string","enum":["low","normal","high","urgent"],"default":"normal","description":"Prioritet for ferie periode (påvirker booking omfordeling)"}}},"VacationPeriod":{"allOf":[{"$ref":"#/components/schemas/CreateVacationRequest"},{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"user_id":{"type":"string","format":"uuid"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"},"is_active":{"type":"boolean","default":true},"status":{"type":"string","enum":["planned","active","completed","cancelled"],"description":"Current vacation status"},"agent":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"role":{"type":"string"}}},"backup_agent":{"type":"object","nullable":true,"properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"role":{"type":"string"}}},"impact_stats":{"type":"object","properties":{"emails_redirected":{"type":"integer","minimum":0},"auto_replies_sent":{"type":"integer","minimum":0},"bookings_reassigned":{"type":"integer","minimum":0}}}}}]},"VacationDetailsResponse":{"allOf":[{"$ref":"#/components/schemas/VacationPeriod"},{"type":"object","properties":{"conflicts":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string","enum":["booking_overlap","agent_unavailable","blackout_conflict"]},"description":{"type":"string"},"affected_dates":{"type":"array","items":{"type":"string","format":"date"}},"severity":{"type":"string","enum":["low","medium","high","critical"]}}}},"recommendations":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string","enum":["backup_agent","redistribute_bookings","adjust_dates","cancel_conflicting"]},"description":{"type":"string"},"action_required":{"type":"boolean"}}}}}}]},"UpdateVacationRequest":{"type":"object","properties":{"title":{"type":"string","minLength":1,"maxLength":200,"description":"Opdateret ferie titel"},"description":{"type":"string","maxLength":1000,"description":"Opdateret beskrivelse"},"start_date":{"type":"string","format":"date","description":"Ny start dato"},"end_date":{"type":"string","format":"date","description":"Ny slut dato"},"backup_agent_id":{"type":"string","format":"uuid","nullable":true,"description":"Ny backup agent"},"auto_reply_enabled":{"type":"boolean","description":"Opdater auto-reply status"},"auto_reply_message":{"type":"string","maxLength":500,"description":"Ny auto-reply besked"},"status":{"type":"string","enum":["planned","active","completed","cancelled"],"description":"Opdater vacation status"}}},"AdminUsersResponse":{"type":"object","properties":{"users":{"type":"array","items":{"$ref":"#/components/schemas/AdminUser"}},"total":{"type":"integer","minimum":0,"description":"Total antal brugere i system"},"pagination":{"$ref":"#/components/schemas/PaginationMeta"},"summary":{"type":"object","properties":{"active_users":{"type":"integer","minimum":0},"trial_users":{"type":"integer","minimum":0},"suspended_users":{"type":"integer","minimum":0},"total_revenue_monthly":{"type":"number","format":"float"},"avg_emails_per_user":{"type":"number","format":"float"}}}}},"AdminUser":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"email":{"type":"string","format":"email"},"full_name":{"type":"string","nullable":true},"subscription_status":{"type":"string","enum":["active","inactive","trial","cancelled","suspended"],"description":"Nuværende subscription status"},"subscription_plan":{"type":"string","enum":["starter","professional","enterprise"],"nullable":true,"description":"Subscription plan type"},"subscription_value":{"type":"number","format":"float","description":"Månedlig subscription værdi i DKK"},"created_at":{"type":"string","format":"date-time"},"last_activity":{"type":"string","format":"date-time","nullable":true,"description":"Sidste aktivitet timestamp"},"usage_stats":{"type":"object","properties":{"total_agents":{"type":"integer","minimum":0},"active_agents":{"type":"integer","minimum":0},"emails_this_month":{"type":"integer","minimum":0},"bookings_this_month":{"type":"integer","minimum":0},"ai_responses_this_month":{"type":"integer","minimum":0}}},"limits":{"type":"object","properties":{"max_agents":{"type":"integer","minimum":-1},"max_emails_monthly":{"type":"integer","minimum":-1},"max_bookings_monthly":{"type":"integer","minimum":-1}}},"flags":{"type":"object","properties":{"is_admin":{"type":"boolean"},"is_suspended":{"type":"boolean"},"requires_onboarding":{"type":"boolean"},"beta_features":{"type":"boolean"}}}}},"AdminAnalyticsResponse":{"type":"object","properties":{"period":{"type":"string","enum":["7d","30d","90d","1y","all"],"description":"Data periode for analytics"},"generated_at":{"type":"string","format":"date-time","description":"Timestamp for rapport generering"},"overview":{"type":"object","properties":{"total_users":{"type":"integer","minimum":0},"active_users":{"type":"integer","minimum":0},"new_signups":{"type":"integer","minimum":0},"churn_rate":{"type":"number","format":"float","minimum":0,"maximum":1},"total_revenue":{"type":"number","format":"float"},"mrr":{"type":"number","format":"float","description":"Monthly Recurring Revenue"},"arr":{"type":"number","format":"float","description":"Annual Recurring Revenue"}}},"email_metrics":{"type":"object","properties":{"total_emails_processed":{"type":"integer","minimum":0},"ai_responses_generated":{"type":"integer","minimum":0},"avg_response_time":{"type":"number","format":"float","description":"I sekunder"},"email_accuracy_rate":{"type":"number","format":"float","minimum":0,"maximum":1}}},"booking_metrics":{"type":"object","properties":{"total_bookings_created":{"type":"integer","minimum":0},"auto_bookings":{"type":"integer","minimum":0},"manual_bookings":{"type":"integer","minimum":0},"booking_success_rate":{"type":"number","format":"float","minimum":0,"maximum":1},"avg_booking_confidence":{"type":"number","format":"float","minimum":0,"maximum":1}}},"subscription_metrics":{"type":"object","properties":{"starter_subscriptions":{"type":"integer","minimum":0},"professional_subscriptions":{"type":"integer","minimum":0},"enterprise_subscriptions":{"type":"integer","minimum":0},"trial_to_paid_conversion":{"type":"number","format":"float","minimum":0,"maximum":1},"avg_subscription_value":{"type":"number","format":"float"}}},"time_series":{"type":"array","items":{"type":"object","properties":{"timestamp":{"type":"string","format":"date-time"},"users":{"type":"integer","minimum":0},"emails":{"type":"integer","minimum":0},"bookings":{"type":"integer","minimum":0},"revenue":{"type":"number","format":"float"}}}}}},"OpenAIStatsResponse":{"type":"object","properties":{"period":{"type":"string","enum":["today","7d","30d","90d"],"description":"Statistics periode"},"generated_at":{"type":"string","format":"date-time","description":"Report generation timestamp"},"usage_summary":{"type":"object","properties":{"total_requests":{"type":"integer","minimum":0},"total_tokens":{"type":"integer","minimum":0},"input_tokens":{"type":"integer","minimum":0},"output_tokens":{"type":"integer","minimum":0},"avg_tokens_per_request":{"type":"number","format":"float"}}},"cost_analysis":{"type":"object","properties":{"total_cost_usd":{"type":"number","format":"float"},"total_cost_dkk":{"type":"number","format":"float"},"avg_cost_per_request":{"type":"number","format":"float"},"cost_per_user":{"type":"number","format":"float"},"cost_trend":{"type":"string","enum":["increasing","decreasing","stable"],"description":"Cost trend sammenlignet med forrige periode"}}},"model_breakdown":{"type":"array","items":{"type":"object","properties":{"model":{"type":"string","example":"gpt-4"},"requests":{"type":"integer","minimum":0},"tokens":{"type":"integer","minimum":0},"cost_usd":{"type":"number","format":"float"},"avg_response_time":{"type":"number","format":"float","description":"I sekunder"}}}},"usage_by_feature":{"type":"array","items":{"type":"object","properties":{"feature":{"type":"string","enum":["email_response","booking_analysis","conversation_summary","agent_training"],"description":"AI feature type"},"requests":{"type":"integer","minimum":0},"tokens":{"type":"integer","minimum":0},"cost_usd":{"type":"number","format":"float"},"success_rate":{"type":"number","format":"float","minimum":0,"maximum":1}}}},"performance_metrics":{"type":"object","properties":{"avg_response_time":{"type":"number","format":"float","description":"I sekunder"},"success_rate":{"type":"number","format":"float","minimum":0,"maximum":1},"error_rate":{"type":"number","format":"float","minimum":0,"maximum":1},"rate_limit_hits":{"type":"integer","minimum":0}}}}},"AdminHealthResponse":{"type":"object","properties":{"status":{"type":"string","enum":["healthy","degraded","critical","maintenance"],"description":"Overall system health status"},"timestamp":{"type":"string","format":"date-time","description":"Health check timestamp"},"uptime":{"type":"number","format":"float","description":"System uptime i sekunder"},"version":{"type":"string","example":"v1.2.0","description":"Current system version"},"services":{"type":"object","properties":{"database":{"type":"object","properties":{"status":{"type":"string","enum":["healthy","degraded","down"]},"response_time":{"type":"number","format":"float","description":"I millisekunder"},"connections":{"type":"integer","minimum":0},"last_check":{"type":"string","format":"date-time"}}},"supabase":{"type":"object","properties":{"status":{"type":"string","enum":["healthy","degraded","down"]},"auth_service":{"type":"string","enum":["healthy","degraded","down"]},"realtime_service":{"type":"string","enum":["healthy","degraded","down"]},"response_time":{"type":"number","format":"float"}}},"openai_api":{"type":"object","properties":{"status":{"type":"string","enum":["healthy","degraded","down"]},"response_time":{"type":"number","format":"float"},"rate_limit_remaining":{"type":"integer","minimum":0},"last_request":{"type":"string","format":"date-time"}}},"gmail_api":{"type":"object","properties":{"status":{"type":"string","enum":["healthy","degraded","down"]},"webhook_status":{"type":"string","enum":["active","inactive","error"]},"quota_remaining":{"type":"integer","minimum":0},"last_sync":{"type":"string","format":"date-time"}}},"stripe_api":{"type":"object","properties":{"status":{"type":"string","enum":["healthy","degraded","down"]},"webhook_status":{"type":"string","enum":["active","inactive","error"]},"last_webhook":{"type":"string","format":"date-time"}}}}},"performance_metrics":{"type":"object","properties":{"avg_api_response_time":{"type":"number","format":"float","description":"I millisekunder"},"requests_per_minute":{"type":"number","format":"float"},"error_rate_5m":{"type":"number","format":"float","minimum":0,"maximum":1},"memory_usage_percent":{"type":"number","format":"float","minimum":0,"maximum":100},"cpu_usage_percent":{"type":"number","format":"float","minimum":0,"maximum":100}}},"alerts":{"type":"array","items":{"type":"object","properties":{"level":{"type":"string","enum":["info","warning","error","critical"]},"service":{"type":"string"},"message":{"type":"string"},"timestamp":{"type":"string","format":"date-time"},"resolved":{"type":"boolean"}}}},"recommendations":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string","enum":["performance","security","cost","maintenance"]},"priority":{"type":"string","enum":["low","medium","high","urgent"]},"title":{"type":"string"},"description":{"type":"string"},"action_required":{"type":"boolean"}}}}}}},"responses":{"BadRequest":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"Unauthorized":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"Forbidden":{"description":"Insufficient permissions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"RateLimited":{"description":"Rate limit exceeded","headers":{"Retry-After":{"description":"Antal sekunder til næste request","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Timestamp for rate limit reset","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Error"},{"type":"object","properties":{"retryAfter":{"type":"integer"},"resetAt":{"type":"string","format":"date-time"}}}]}}}},"NotFound":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"x-api-key","description":"API key authentication til programmatisk adgang. Bruges til webhook endpoints, automatiserede integrationer og backend services.\n\n**Key Formater:**\n- Live keys: `agently_live_sk_[32_karakterer]` (production data)\n- Test keys: `agently_test_sk_[32_karakterer]` (sandbox miljø)\n\n**Permissions:**\n- `read:bookings` - Læs booking data\n- `write:bookings` - Opret og modificer bookings\n- `read:agents` - Læs AI agent konfiguration\n- `write:agents` - Administrer AI agents\n- `read:conversations` - Adgang til kunde samtaler\n- `write:conversations` - Deltag i samtaler og manual takeover\n- `read:analytics` - Performance metrics og rapporter\n- `webhook:receive` - Modtag webhook notifications\n\n**Rate Limits:**\n- Standard: 1000 requests/time\n- Premium: 5000 requests/time  \n- Enterprise: 25000 requests/time\n\n**Security:**\n- Gem aldrig API keys i frontend kode\n- Brug HTTPS for alle requests\n- Rotér keys regelmæssigt (anbefalet: hver 90 dage)\n- Brug mindste privilegium princip"},"SessionAuth":{"type":"http","scheme":"bearer","description":"Session-baseret authentication til dashboard og interaktive applikationer. Bruges automatisk af web frontend.\n\n**Session Management:**\n- Automatisk cookie-baseret sessions\n- 24 timers udløbstid (standard)\n- Sliding expiration ved aktivitet\n- Secure og HttpOnly cookies\n\n**Multi-Factor Authentication:**\n- TOTP (Time-based One-Time Password) support\n- SMS backup codes\n- Recovery key options\n\n**Session Security:**\n- CSRF protection aktiveret\n- SameSite cookies (Strict mode)\n- Session rotation ved privilegium eskalation\n- Geografisk lokation tracking"},"WebhookAuth":{"type":"apiKey","in":"header","name":"x-webhook-signature","description":"HMAC-SHA256 signatur verification til webhook endpoints. Sikrer at webhooks kommer fra Agently platform.\n\n**Signature Verification:**\n1. Kombiner timestamp + payload body\n2. Beregn HMAC-SHA256 med din webhook secret\n3. Sammenlign med `x-webhook-signature` header\n4. Verificer timestamp er inden for 5 minutter\n\n**Header Format:**\n```\nx-webhook-signature: t=1642694400,v1=5257a869e7ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8bd\n```\n\n**Eksempel (Node.js):**\n```javascript\nconst crypto = require('crypto');\n\nfunction verifyWebhook(payload, signature, secret) {\n  const timestamp = signature.split(',')[0].split('=')[1];\n  const hash = signature.split(',')[1].split('=')[1];\n  \n  const signedPayload = timestamp + '.' + payload;\n  const expectedHash = crypto\n    .createHmac('sha256', secret)\n    .update(signedPayload)\n    .digest('hex');\n    \n  return crypto.timingSafeEqual(\n    Buffer.from(hash, 'hex'),\n    Buffer.from(expectedHash, 'hex')\n  );\n}\n```\n\n**Security Tips:**\n- Brug timing-safe sammenligning\n- Verificer timestamp for replay attacks\n- Log failed verification attempts  \n- Rotér webhook secrets regelmæssigt"},"OAuth2":{"type":"oauth2","description":"OAuth 2.0 integration til email providers og tredjeparts services. Bruges til Gmail API, Outlook integration mv.\n\n**Supported Providers:**\n- Google Gmail (OAuth 2.0 + PKCE)\n- Microsoft Outlook/Exchange (OAuth 2.0)\n- Custom IMAP (Basic Auth fallback)\n\n**Scopes:**\n- `email.read` - Læs emails fra provider\n- `email.send` - Send emails via provider\n- `calendar.read` - Læs kalender events\n- `calendar.write` - Opret/opdater kalender events\n- `contacts.read` - Adgang til kontaktlister\n\n**Gmail Integration:**\n- Automatisk webhook setup via Pub/Sub\n- Real-time email notifications\n- Thread-baseret samtale tracking\n- Batch operations til performance\n\n**Security:**\n- PKCE (Proof Key for Code Exchange) aktiveret\n- State parameter for CSRF protection\n- Refresh token rotation\n- Scope limitation per use case"}},"x-rate-limiting":{"description":"Agently API implementerer intelligent rate limiting for at sikre fair usage og platform stabilitet.\n\n**Rate Limit Tiers:**\n- **Free Tier**: 100 requests/time (burst: 20 requests/10 sek)\n- **Starter**: 1.000 requests/time (burst: 50 requests/10 sek)  \n- **Professional**: 5.000 requests/time (burst: 100 requests/10 sek)\n- **Enterprise**: 25.000 requests/time (burst: 500 requests/10 sek)\n\n**Headers i Response:**\n```\nX-RateLimit-Limit: 1000          # Total limit per time\nX-RateLimit-Remaining: 999       # Requests tilbage i periode\nX-RateLimit-Reset: 1642694460    # Unix timestamp for reset\nX-RateLimit-Reset-After: 59      # Sekunder til reset\nX-RateLimit-Burst-Limit: 50     # Burst capacity\nX-RateLimit-Burst-Remaining: 49  # Burst requests tilbage\n```\n\n**Rate Limit Algoritmer:**\n- **Token Bucket**: For burst capacity (korte spikes tilladt)\n- **Sliding Window**: For time-baserede limits (smooth enforcement)  \n- **Per-Endpoint Limits**: Specielle limits for ressource-intensive endpoints\n\n**Endpoint-Specific Limits:**\n- `POST /bookings`: 100/time (auto-booking protection)\n- `POST /conversations/{id}/messages`: 30/minut (spam protection)\n- `POST /email-filters`: 10/minut (filter creation limit)\n- `GET /agents/{id}/conversations`: 500/time (data export limit)\n- `POST /webhooks/*`: 1000/time (webhook processing)\n\n**429 Rate Limited Response:**\n```json\n{\n  \"error\": \"rate_limit_exceeded\",\n  \"message\": \"Rate limit på 1000 requests/time overskredet\",\n  \"retry_after\": 59,\n  \"reset_time\": \"2024-01-20T15:01:00Z\",\n  \"current_usage\": {\n    \"requests_made\": 1001,\n    \"window_limit\": 1000,\n    \"burst_used\": 45,\n    \"burst_limit\": 50\n  },\n  \"upgrade_available\": {\n    \"next_tier\": \"Professional\",\n    \"new_limit\": 5000,\n    \"pricing_url\": \"https://agently.dk/pricing\"\n  }\n}\n```\n\n**Best Practices:**\n- Implementer exponential backoff ved 429 errors\n- Cache API responses hvor muligt\n- Brug webhook events i stedet for polling\n- Batch requests når API'et understøtter det\n- Monitor dine rate limits via headers"},"x-authentication":{"description":"Comprehensive authentication guide for Agently API integration.\n\n**Authentication Methods by Use Case:**\n\n1. **Backend Integration** → API Keys\n   - Server-to-server kommunikation\n   - Webhook endpoints  \n   - Automatiserede processer\n   - Batch operations\n\n2. **Frontend Applications** → Session Auth\n   - Dashboard og web apps\n   - Real-time user interaktioner\n   - Interactive customer portals\n   - Admin interfaces\n\n3. **Third-party Services** → OAuth 2.0\n   - Gmail/Outlook integration\n   - Kalender synkronisering\n   - Contact list imports\n   - Email automation platforms\n\n4. **Webhooks** → HMAC Signature\n   - Indgående webhook events\n   - Payload verification\n   - Replay attack prevention\n   - Integrity validation\n\n**Security Checklist:**\n□ Brug HTTPS for alle API calls\n□ Gem API keys sikkert (environment variables)\n□ Implementer proper error handling\n□ Log authentication failures\n□ Rotér credentials regelmæssigt\n□ Validér webhook signatures\n□ Monitor for suspicious activity\n□ Implementér rate limit handling\n\n**Development Flow:**\n1. **Test Environment**: Brug `agently_test_*` keys\n2. **Staging**: Separate keys for staging miljø  \n3. **Production**: `agently_live_*` keys med begrænsede permissions\n4. **Monitoring**: Setup alerting for authentication failures\n\n**Common Authentication Errors:**\n- `401 Unauthorized`: Manglende eller ugyldig API key\n- `403 Forbidden`: API key mangler required permissions\n- `429 Too Many Requests`: Rate limit overskredet\n- `498 Invalid Token`: Udløbet eller korrupt session token"},"x-integration-examples":{"description":"Comprehensive integration examples and real-world use cases for the Agently AI platform.\n\n## 🚀 Quick Start Guide\n\n### 1. Basic Setup (Node.js)\n```javascript\n// Install dependencies\nnpm install axios dotenv\n\n// Basic Agently API client\nconst axios = require('axios');\n\nclass AgentlyClient {\n  constructor(apiKey) {\n    this.apiKey = apiKey;\n    this.baseURL = 'https://api.agently.dk/v1';\n    this.client = axios.create({\n      baseURL: this.baseURL,\n      headers: {\n        'x-api-key': apiKey,\n        'Content-Type': 'application/json',\n        'User-Agent': 'AgentlyClient/1.0'\n      }\n    });\n    \n    // Add rate limiting handling\n    this.client.interceptors.response.use(\n      response => response,\n      error => {\n        if (error.response?.status === 429) {\n          const retryAfter = error.response.headers['retry-after'] || 60;\n          console.log(`Rate limited. Retrying after ${retryAfter} seconds`);\n          return new Promise(resolve => {\n            setTimeout(() => resolve(this.client.request(error.config)), retryAfter * 1000);\n          });\n        }\n        return Promise.reject(error);\n      }\n    );\n  }\n  \n  // Create AI agent\n  async createAgent(agentData) {\n    const response = await this.client.post('/agents', agentData);\n    return response.data;\n  }\n  \n  // Get agent conversations\n  async getAgentConversations(agentId, options = {}) {\n    const params = new URLSearchParams(options);\n    const response = await this.client.get(`/agents/${agentId}/conversations?${params}`);\n    return response.data;\n  }\n  \n  // Create booking\n  async createBooking(bookingData) {\n    const response = await this.client.post('/bookings', bookingData);\n    return response.data;\n  }\n}\n\n// Usage\nconst client = new AgentlyClient(process.env.AGENTLY_API_KEY);\n```\n\n### 2. Multi-Language SDK Examples\n\n#### Python (Django/Flask/FastAPI)\n```python\n# pip install requests python-dotenv\nimport os\nimport requests\nfrom typing import Optional, Dict, Any\nfrom dotenv import load_dotenv\n\nload_dotenv()\n\nclass AgentlyClient:\n    def __init__(self, api_key: str):\n        self.api_key = api_key\n        self.base_url = 'https://api.agently.dk/v1'\n        self.session = requests.Session()\n        self.session.headers.update({\n            'x-api-key': api_key,\n            'Content-Type': 'application/json',\n            'User-Agent': 'AgentlyClient-Python/1.0'\n        })\n    \n    def _handle_rate_limit(self, response: requests.Response) -> requests.Response:\n        \"\"\"Handle rate limiting with exponential backoff\"\"\"\n        if response.status_code == 429:\n            retry_after = int(response.headers.get('retry-after', 60))\n            print(f\"Rate limited. Retrying after {retry_after} seconds\")\n            import time\n            time.sleep(retry_after)\n            return self.session.request(\n                response.request.method,\n                response.request.url,\n                **response.request.__dict__.get('kwargs', {})\n            )\n        return response\n    \n    def create_agent(self, agent_data: Dict[str, Any]) -> Dict[str, Any]:\n        \"\"\"Create a new AI agent\"\"\"\n        response = self.session.post(f'{self.base_url}/agents', json=agent_data)\n        response = self._handle_rate_limit(response)\n        response.raise_for_status()\n        return response.json()\n    \n    def get_agent_conversations(self, agent_id: str, **params) -> Dict[str, Any]:\n        \"\"\"Get conversations for an agent\"\"\"\n        response = self.session.get(\n            f'{self.base_url}/agents/{agent_id}/conversations',\n            params=params\n        )\n        response = self._handle_rate_limit(response)\n        response.raise_for_status()\n        return response.json()\n    \n    def create_booking(self, booking_data: Dict[str, Any]) -> Dict[str, Any]:\n        \"\"\"Create a new booking\"\"\"\n        response = self.session.post(f'{self.base_url}/bookings', json=booking_data)\n        response = self._handle_rate_limit(response)\n        response.raise_for_status()\n        return response.json()\n\n# Usage\nclient = AgentlyClient(os.getenv('AGENTLY_API_KEY'))\n\n# Example: Create agent in Django view\ndef create_sales_agent(request):\n    try:\n        agent = client.create_agent({\n            'name': 'Emma Sales',\n            'role': 'sales',\n            'personality': 'Professional, venlig og hjælpsom',\n            'instructions': 'Du er en sales agent for en dansk virksomhed.'\n        })\n        return JsonResponse({'success': True, 'agent': agent})\n    except requests.exceptions.HTTPError as e:\n        return JsonResponse({'error': str(e)}, status=400)\n```\n\n#### PHP (Laravel/WordPress)\n```php\n<?php\n// composer require guzzlehttp/guzzle vlucas/phpdotenv\nrequire_once 'vendor/autoload.php';\n\nuse GuzzleHttp\\Client;\nuse GuzzleHttp\\Exception\\RequestException;\n\nclass AgentlyClient {\n    private $apiKey;\n    private $baseUrl;\n    private $client;\n    \n    public function __construct($apiKey) {\n        $this->apiKey = $apiKey;\n        $this->baseUrl = 'https://api.agently.dk/v1';\n        $this->client = new Client([\n            'base_uri' => $this->baseUrl,\n            'headers' => [\n                'x-api-key' => $apiKey,\n                'Content-Type' => 'application/json',\n                'User-Agent' => 'AgentlyClient-PHP/1.0'\n            ],\n            'timeout' => 30\n        ]);\n    }\n    \n    private function handleRateLimit($response, $originalRequest) {\n        if ($response->getStatusCode() === 429) {\n            $retryAfter = $response->getHeader('retry-after')[0] ?? 60;\n            error_log(\"Rate limited. Retrying after {$retryAfter} seconds\");\n            sleep($retryAfter);\n            return $this->client->send($originalRequest);\n        }\n        return $response;\n    }\n    \n    public function createAgent($agentData) {\n        try {\n            $response = $this->client->post('/agents', [\n                'json' => $agentData\n            ]);\n            \n            return json_decode($response->getBody(), true);\n        } catch (RequestException $e) {\n            if ($e->getCode() === 429) {\n                return $this->handleRateLimit($e->getResponse(), $e->getRequest());\n            }\n            throw $e;\n        }\n    }\n    \n    public function getAgentConversations($agentId, $params = []) {\n        try {\n            $response = $this->client->get(\"/agents/{$agentId}/conversations\", [\n                'query' => $params\n            ]);\n            \n            return json_decode($response->getBody(), true);\n        } catch (RequestException $e) {\n            throw new Exception('Failed to get conversations: ' . $e->getMessage());\n        }\n    }\n    \n    public function createBooking($bookingData) {\n        try {\n            $response = $this->client->post('/bookings', [\n                'json' => $bookingData\n            ]);\n            \n            return json_decode($response->getBody(), true);\n        } catch (RequestException $e) {\n            throw new Exception('Failed to create booking: ' . $e->getMessage());\n        }\n    }\n}\n\n// Usage (Laravel)\n$dotenv = Dotenv\\Dotenv::createImmutable(__DIR__);\n$dotenv->load();\n\n$client = new AgentlyClient($_ENV['AGENTLY_API_KEY']);\n\n// Laravel Controller example\nclass AgentController extends Controller {\n    public function store(Request $request) {\n        $client = new AgentlyClient(env('AGENTLY_API_KEY'));\n        \n        try {\n            $agent = $client->createAgent([\n                'name' => $request->name,\n                'role' => $request->role,\n                'personality' => $request->personality,\n                'instructions' => $request->instructions\n            ]);\n            \n            return response()->json(['success' => true, 'agent' => $agent]);\n        } catch (Exception $e) {\n            return response()->json(['error' => $e->getMessage()], 400);\n        }\n    }\n}\n?>\n```\n\n#### cURL (Command Line/Shell Scripts)\n```bash\n#!/bin/bash\n# Agently API cURL examples with error handling and rate limiting\n\n# Configuration\nAGENTLY_API_KEY=\"agently_test_sk_your_32_character_test_key_here\"\nBASE_URL=\"https://api.agently.dk/v1\"\n\n# Helper function for API requests with rate limiting\napi_request() {\n    local method=\"$1\"\n    local endpoint=\"$2\"\n    local data=\"$3\"\n    local max_retries=3\n    local retry_count=0\n    \n    while [ $retry_count -lt $max_retries ]; do\n        if [ \"$method\" = \"GET\" ]; then\n            response=$(curl -s -w \"\\n%{http_code}\" \\\n                -H \"x-api-key: $AGENTLY_API_KEY\" \\\n                -H \"Content-Type: application/json\" \\\n                -H \"User-Agent: AgentlyClient-cURL/1.0\" \\\n                \"$BASE_URL$endpoint\")\n        else\n            response=$(curl -s -w \"\\n%{http_code}\" \\\n                -X \"$method\" \\\n                -H \"x-api-key: $AGENTLY_API_KEY\" \\\n                -H \"Content-Type: application/json\" \\\n                -H \"User-Agent: AgentlyClient-cURL/1.0\" \\\n                -d \"$data\" \\\n                \"$BASE_URL$endpoint\")\n        fi\n        \n        http_code=$(echo \"$response\" | tail -n1)\n        response_body=$(echo \"$response\" | head -n -1)\n        \n        case $http_code in\n            200|201)\n                echo \"$response_body\"\n                return 0\n                ;;\n            429)\n                retry_after=$(echo \"$response_body\" | jq -r '.retry_after // 60')\n                echo \"Rate limited. Waiting $retry_after seconds...\" >&2\n                sleep \"$retry_after\"\n                ((retry_count++))\n                ;;\n            *)\n                echo \"HTTP Error $http_code: $response_body\" >&2\n                return 1\n                ;;\n        esac\n    done\n    \n    echo \"Max retries exceeded\" >&2\n    return 1\n}\n\n# Create AI Agent\ncreate_agent() {\n    local agent_data='{\n        \"name\": \"Emma Sales\",\n        \"role\": \"sales\",\n        \"personality\": \"Professional, venlig og hjælpsom\",\n        \"instructions\": \"Du er en sales agent for en dansk virksomhed. Svar altid på dansk.\",\n        \"working_hours\": {\n            \"start\": \"08:00\",\n            \"end\": \"18:00\",\n            \"timezone\": \"Europe/Copenhagen\"\n        },\n        \"auto_booking\": {\n            \"enabled\": true,\n            \"confidence_threshold\": 0.85\n        }\n    }'\n    \n    echo \"Creating AI agent...\"\n    result=$(api_request \"POST\" \"/agents\" \"$agent_data\")\n    \n    if [ $? -eq 0 ]; then\n        agent_id=$(echo \"$result\" | jq -r '.id')\n        echo \"✅ Agent created successfully: $agent_id\"\n        return 0\n    else\n        echo \"❌ Failed to create agent\"\n        return 1\n    fi\n}\n\n# Get Agent Conversations\nget_conversations() {\n    local agent_id=\"$1\"\n    local limit=\"${2:-10}\"\n    \n    echo \"Fetching conversations for agent $agent_id...\"\n    result=$(api_request \"GET\" \"/agents/$agent_id/conversations?limit=$limit\")\n    \n    if [ $? -eq 0 ]; then\n        echo \"$result\" | jq '.conversations[] | {id, customer_email, subject, status}'\n        return 0\n    else\n        echo \"❌ Failed to fetch conversations\"\n        return 1\n    fi\n}\n\n# Create Booking\ncreate_booking() {\n    local booking_data='{\n        \"customer_email\": \"kunde@example.com\",\n        \"customer_name\": \"Test Kunde\",\n        \"meeting_title\": \"Sales Demo\",\n        \"scheduled_start\": \"2024-03-20T10:00:00Z\",\n        \"scheduled_end\": \"2024-03-20T11:00:00Z\",\n        \"agent_id\": \"'$1'\",\n        \"meeting_title\": \"Video møde\"\n    }'\n    \n    echo \"Creating booking...\"\n    result=$(api_request \"POST\" \"/bookings\" \"$booking_data\")\n    \n    if [ $? -eq 0 ]; then\n        booking_id=$(echo \"$result\" | jq -r '.id')\n        echo \"✅ Booking created successfully: $booking_id\"\n        return 0\n    else\n        echo \"❌ Failed to create booking\"\n        return 1\n    fi\n}\n\n# Main execution\necho \"🚀 Starting Agently API integration test...\"\n\nif create_agent; then\n    agent_id=$(api_request \"GET\" \"/agents?limit=1\" | jq -r '.agents[0].id')\n    get_conversations \"$agent_id\"\n    create_booking \"$agent_id\"\nfi\n\necho \"✨ Integration test completed\"\n```\n\n#### Ruby (Rails)\n```ruby\n# Gemfile\n# gem 'faraday'\n# gem 'faraday-retry'\n# gem 'dotenv-rails'\n\nrequire 'faraday'\nrequire 'faraday/retry'\nrequire 'json'\nrequire 'dotenv/load'\n\nclass AgentlyClient\n  BASE_URL = 'https://api.agently.dk/v1'.freeze\n  \n  def initialize(api_key)\n    @api_key = api_key\n    @connection = Faraday.new(BASE_URL) do |conn|\n      conn.request :json\n      conn.request :retry, max: 3, interval: 1, backoff_factor: 2,\n                   exceptions: [Faraday::ServerError, Faraday::TooManyRequestsError]\n      conn.response :json\n      conn.adapter Faraday.default_adapter\n      \n      conn.headers['x-api-key'] = api_key\n      conn.headers['Content-Type'] = 'application/json'\n      conn.headers['User-Agent'] = 'AgentlyClient-Ruby/1.0'\n    end\n  end\n  \n  def create_agent(agent_data)\n    response = @connection.post('/agents', agent_data)\n    handle_response(response)\n  end\n  \n  def get_agent_conversations(agent_id, options = {})\n    response = @connection.get(\"/agents/#{agent_id}/conversations\", options)\n    handle_response(response)\n  end\n  \n  def create_booking(booking_data)\n    response = @connection.post('/bookings', booking_data)\n    handle_response(response)\n  end\n  \n  private\n  \n  def handle_response(response)\n    case response.status\n    when 200..299\n      response.body\n    when 400\n      raise StandardError, \"Bad Request: #{response.body}\"\n    when 401\n      raise StandardError, \"Unauthorized: Check your API key\"\n    when 429\n      retry_after = response.headers['retry-after']&.to_i || 60\n      puts \"Rate limited. Retrying after #{retry_after} seconds\"\n      sleep(retry_after)\n      raise Faraday::TooManyRequestsError\n    when 500..599\n      raise StandardError, \"Server Error: #{response.body}\"\n    else\n      raise StandardError, \"Unexpected response: #{response.status}\"\n    end\n  end\nend\n\n# Usage (Rails Controller)\nclass AgentsController < ApplicationController\n  before_action :initialize_client\n  \n  def create\n    agent = @client.create_agent(agent_params)\n    render json: { success: true, agent: agent }\n  rescue StandardError => e\n    render json: { error: e.message }, status: :bad_request\n  end\n  \n  def conversations\n    conversations = @client.get_agent_conversations(params[:id], limit: 10)\n    render json: conversations\n  rescue StandardError => e\n    render json: { error: e.message }, status: :bad_request\n  end\n  \n  private\n  \n  def initialize_client\n    @client = AgentlyClient.new(ENV['AGENTLY_API_KEY'])\n  end\n  \n  def agent_params\n    params.require(:agent).permit(:name, :role, :personality, :instructions)\n  end\nend\n\n# Example usage\nclient = AgentlyClient.new(ENV['AGENTLY_API_KEY'])\n\nagent = client.create_agent({\n  name: 'Emma Sales',\n  role: 'sales',\n  personality: 'Professional, venlig og hjælpsom',\n  instructions: 'Du er en sales agent for en dansk virksomhed.'\n})\n\nputs \"✅ Agent created: #{agent['id']}\"\n```\n\n#### Go (Microservices)\n```go\npackage main\n\nimport (\n    \"bytes\"\n    \"encoding/json\"\n    \"fmt\"\n    \"io\"\n    \"net/http\"\n    \"os\"\n    \"time\"\n)\n\ntype AgentlyClient struct {\n    APIKey     string\n    BaseURL    string\n    HTTPClient *http.Client\n}\n\ntype Agent struct {\n    ID           string `json:\"id,omitempty\"`\n    Name         string `json:\"name\"`\n    Role         string `json:\"role\"`\n    Personality  string `json:\"personality\"`\n    Instructions string `json:\"instructions\"`\n}\n\ntype Conversation struct {\n    ID            string `json:\"id\"`\n    CustomerEmail string `json:\"customer_email\"`\n    Subject       string `json:\"subject\"`\n    Status        string `json:\"status\"`\n}\n\ntype Booking struct {\n    ID             string    `json:\"id,omitempty\"`\n    CustomerEmail  string    `json:\"customer_email\"`\n    CustomerName   string    `json:\"customer_name\"`\n    MeetingTitle   string    `json:\"meeting_title\"`\n    ScheduledStart time.Time `json:\"scheduled_start\"`\n    ScheduledEnd   time.Time `json:\"scheduled_end\"`\n    AgentID        string    `json:\"agent_id\"`\n}\n\nfunc NewAgentlyClient(apiKey string) *AgentlyClient {\n    return &AgentlyClient{\n        APIKey:  apiKey,\n        BaseURL: \"https://api.agently.dk/v1\",\n        HTTPClient: &http.Client{\n            Timeout: time.Second * 30,\n        },\n    }\n}\n\nfunc (c *AgentlyClient) makeRequest(method, endpoint string, body interface{}) ([]byte, error) {\n    var reqBody io.Reader\n    \n    if body != nil {\n        jsonData, err := json.Marshal(body)\n        if err != nil {\n            return nil, fmt.Errorf(\"failed to marshal request body: %w\", err)\n        }\n        reqBody = bytes.NewBuffer(jsonData)\n    }\n    \n    req, err := http.NewRequest(method, c.BaseURL+endpoint, reqBody)\n    if err != nil {\n        return nil, fmt.Errorf(\"failed to create request: %w\", err)\n    }\n    \n    req.Header.Set(\"x-api-key\", c.APIKey)\n    req.Header.Set(\"Content-Type\", \"application/json\")\n    req.Header.Set(\"User-Agent\", \"AgentlyClient-Go/1.0\")\n    \n    maxRetries := 3\n    for i := 0; i < maxRetries; i++ {\n        resp, err := c.HTTPClient.Do(req)\n        if err != nil {\n            return nil, fmt.Errorf(\"request failed: %w\", err)\n        }\n        defer resp.Body.Close()\n        \n        respBody, err := io.ReadAll(resp.Body)\n        if err != nil {\n            return nil, fmt.Errorf(\"failed to read response: %w\", err)\n        }\n        \n        switch resp.StatusCode {\n        case 200, 201:\n            return respBody, nil\n        case 429: // Rate limited\n            retryAfter := resp.Header.Get(\"retry-after\")\n            if retryAfter == \"\" {\n                time.Sleep(60 * time.Second)\n            } else {\n                // Parse retry-after header and wait\n                time.Sleep(60 * time.Second) // Simplified\n            }\n            continue\n        default:\n            return nil, fmt.Errorf(\"API error %d: %s\", resp.StatusCode, string(respBody))\n        }\n    }\n    \n    return nil, fmt.Errorf(\"max retries exceeded\")\n}\n\nfunc (c *AgentlyClient) CreateAgent(agent Agent) (*Agent, error) {\n    respBody, err := c.makeRequest(\"POST\", \"/agents\", agent)\n    if err != nil {\n        return nil, err\n    }\n    \n    var createdAgent Agent\n    if err := json.Unmarshal(respBody, &createdAgent); err != nil {\n        return nil, fmt.Errorf(\"failed to unmarshal response: %w\", err)\n    }\n    \n    return &createdAgent, nil\n}\n\nfunc (c *AgentlyClient) GetAgentConversations(agentID string) ([]Conversation, error) {\n    respBody, err := c.makeRequest(\"GET\", fmt.Sprintf(\"/agents/%s/conversations\", agentID), nil)\n    if err != nil {\n        return nil, err\n    }\n    \n    var result struct {\n        Conversations []Conversation `json:\"conversations\"`\n    }\n    if err := json.Unmarshal(respBody, &result); err != nil {\n        return nil, fmt.Errorf(\"failed to unmarshal response: %w\", err)\n    }\n    \n    return result.Conversations, nil\n}\n\nfunc (c *AgentlyClient) CreateBooking(booking Booking) (*Booking, error) {\n    respBody, err := c.makeRequest(\"POST\", \"/bookings\", booking)\n    if err != nil {\n        return nil, err\n    }\n    \n    var createdBooking Booking\n    if err := json.Unmarshal(respBody, &createdBooking); err != nil {\n        return nil, fmt.Errorf(\"failed to unmarshal response: %w\", err)\n    }\n    \n    return &createdBooking, nil\n}\n\nfunc main() {\n    // Usage example\n    client := NewAgentlyClient(os.Getenv(\"AGENTLY_API_KEY\"))\n    \n    // Create agent\n    agent, err := client.CreateAgent(Agent{\n        Name:         \"Emma Sales\",\n        Role:         \"sales\",\n        Personality:  \"Professional, venlig og hjælpsom\",\n        Instructions: \"Du er en sales agent for en dansk virksomhed.\",\n    })\n    if err != nil {\n        fmt.Printf(\"❌ Failed to create agent: %v\\n\", err)\n        return\n    }\n    \n    fmt.Printf(\"✅ Agent created: %s\\n\", agent.ID)\n    \n    // Get conversations\n    conversations, err := client.GetAgentConversations(agent.ID)\n    if err != nil {\n        fmt.Printf(\"❌ Failed to get conversations: %v\\n\", err)\n        return\n    }\n    \n    fmt.Printf(\"📧 Found %d conversations\\n\", len(conversations))\n    \n    // Create booking\n    booking, err := client.CreateBooking(Booking{\n        CustomerEmail:  \"kunde@example.com\",\n        CustomerName:   \"Test Kunde\",\n        MeetingTitle:   \"Sales Demo\",\n        ScheduledStart: time.Now().Add(24 * time.Hour),\n        ScheduledEnd:   time.Now().Add(25 * time.Hour),\n        AgentID:        agent.ID,\n    })\n    if err != nil {\n        fmt.Printf(\"❌ Failed to create booking: %v\\n\", err)\n        return\n    }\n    \n    fmt.Printf(\"✅ Booking created: %s\\n\", booking.ID)\n}\n```\n\n### 3. Environment Configuration\n```env\n# .env file\nAGENTLY_API_KEY=agently_test_sk_your_32_character_test_key_here\nWEBHOOK_SECRET=your_webhook_secret_here\nNEXT_PUBLIC_AGENTLY_ENV=test\n```\n\n## 🤖 AI Agent Management\n\n### Create and Configure AI Agent\n```javascript\nasync function setupSalesAgent() {\n  const agentData = {\n    name: \"Emma Sales\",\n    role: \"sales\",\n    personality: \"Professional, venlig og hjælpsom. Fokuserer på kundens behov og løsninger.\",\n    instructions: \"Du er en sales agent for en dansk virksomhed. Svar altid på dansk og hold en professionel men personlig tone. Fokuser på at forstå kundens behov og tilbyd relevante løsninger.\",\n    working_hours: {\n      start: \"08:00\",\n      end: \"18:00\", \n      timezone: \"Europe/Copenhagen\",\n      days: [\"monday\", \"tuesday\", \"wednesday\", \"thursday\", \"friday\"]\n    },\n    auto_booking: {\n      enabled: true,\n      confidence_threshold: 0.85,\n      max_meetings_per_day: 5\n    },\n    business_context: {\n      company_name: \"Din Virksomhed A/S\",\n      industry: \"SaaS/Software\",\n      target_customers: \"Danske SMV virksomheder\",\n      key_products: [\"AI email agent\", \"Booking automatisering\", \"Customer service\"],\n      pricing_tiers: [\"Starter: 299 DKK\", \"Professional: 699 DKK\", \"Enterprise: 1299 DKK\"]\n    }\n  };\n  \n  try {\n    const agent = await client.createAgent(agentData);\n    console.log('✅ Sales agent created:', agent.id);\n    \n    // Setup availability\n    await client.post(`/agents/${agent.id}/availability`, {\n      schedule: [\n        { day_of_week: 1, start_time: \"08:00\", end_time: \"18:00\" },\n        { day_of_week: 2, start_time: \"08:00\", end_time: \"18:00\" },\n        { day_of_week: 3, start_time: \"08:00\", end_time: \"18:00\" },\n        { day_of_week: 4, start_time: \"08:00\", end_time: \"18:00\" },\n        { day_of_week: 5, start_time: \"08:00\", end_time: \"18:00\" }\n      ]\n    });\n    \n    return agent;\n  } catch (error) {\n    console.error('❌ Agent creation failed:', error.response?.data);\n    throw error;\n  }\n}\n```\n\n### Auto-Booking Configuration\n```javascript\nasync function configureAutoBooking(agentId) {\n  const autoBookingConfig = {\n    enabled: true,\n    confidence_threshold: 0.85, // 85% AI confidence required\n    business_rules: {\n      max_meetings_per_day: 5,\n      booking_buffer_minutes: 15, // 15 min mellem møder\n      advance_booking_days: 30, // Book max 30 dage frem\n      block_same_day_bookings: false,\n      require_phone_number: false,\n      allowed_durations: [30, 60, 90] // Tilladt møde længder i minutter\n    },\n    email_templates: {\n      confirmation: {\n        subject: \"Møde bekræftet: {{meeting_title}}\",\n        template: `Hej {{customer_name}},\n\nDit møde er nu bekræftet:\n\n📅 **Tidspunkt**: {{formatted_date}}\n⏰ **Varighed**: {{duration}} minutter  \n👤 **Med**: {{agent_name}}\n📝 **Emne**: {{meeting_title}}\n\n{{#if meeting_description}}\n**Beskrivelse**: {{meeting_description}}\n{{/if}}\n\nVi glæder os til at tale med dig!\n\nVenlig hilsen,\n{{company_name}} Team`\n      }\n    }\n  };\n  \n  const response = await client.put(`/agents/${agentId}/auto-booking`, autoBookingConfig);\n  return response.data;\n}\n```\n\n## 📧 Email Integration & Webhooks\n\n### Gmail Webhook Setup\n```javascript\nconst express = require('express');\nconst crypto = require('crypto');\nconst app = express();\n\n// Webhook signature verification\nfunction verifyWebhookSignature(payload, signature, secret) {\n  const timestamp = signature.split(',')[0].split('=')[1];\n  const hash = signature.split(',')[1].split('=')[1];\n  \n  // Check timestamp (reject if > 5 minutes old)\n  const now = Math.floor(Date.now() / 1000);\n  if (Math.abs(now - timestamp) > 300) {\n    throw new Error('Webhook timestamp too old');\n  }\n  \n  const signedPayload = timestamp + '.' + payload;\n  const expectedHash = crypto\n    .createHmac('sha256', secret)\n    .update(signedPayload)\n    .digest('hex');\n    \n  return crypto.timingSafeEqual(\n    Buffer.from(hash, 'hex'),\n    Buffer.from(expectedHash, 'hex')\n  );\n}\n\n// Gmail webhook handler\napp.post('/webhooks/gmail', express.raw({type: 'application/json'}), (req, res) => {\n  try {\n    const signature = req.headers['x-webhook-signature'];\n    const payload = req.body;\n    \n    // Verify signature\n    if (!verifyWebhookSignature(payload.toString(), signature, process.env.WEBHOOK_SECRET)) {\n      return res.status(401).json({ error: 'Invalid webhook signature' });\n    }\n    \n    const webhookData = JSON.parse(payload.toString());\n    \n    switch (webhookData.event) {\n      case 'email.received':\n        await handleIncomingEmail(webhookData.data);\n        break;\n        \n      case 'email.filtered':\n        await handleFilteredEmail(webhookData.data);  \n        break;\n        \n      case 'conversation.started':\n        await notifyTeam(webhookData.data);\n        break;\n        \n      default:\n        console.log('Unknown webhook event:', webhookData.event);\n    }\n    \n    res.json({ success: true });\n  } catch (error) {\n    console.error('Webhook processing failed:', error);\n    res.status(500).json({ error: 'Webhook processing failed' });\n  }\n});\n\nasync function handleIncomingEmail(emailData) {\n  console.log(`📧 New email from ${emailData.from}: ${emailData.subject}`);\n  \n  // Route to appropriate agent based on email content\n  const agentId = await routeEmailToAgent(emailData);\n  \n  // Auto-respond if confidence is high\n  if (emailData.ai_confidence > 0.9) {\n    await client.post(`/conversations/${emailData.conversation_id}/messages`, {\n      content: `Tak for din henvendelse. Jeg har modtaget din besked og vender tilbage hurtigst muligt.`,\n      is_ai_response: true\n    });\n  }\n}\n```\n\n## 📅 Booking System Integration\n\n### Complete Booking Flow\n```javascript\nclass BookingManager {\n  constructor(agentlyClient) {\n    this.client = agentlyClient;\n  }\n  \n  async createBookingFromEmail(emailData, customerInfo) {\n    try {\n      // 1. Extract meeting details using AI\n      const meetingDetails = await this.extractMeetingDetails(emailData.content);\n      \n      // 2. Find available agent\n      const agent = await this.findAvailableAgent(meetingDetails.preferredTime, meetingDetails.topic);\n      \n      // 3. Check for conflicts\n      const conflicts = await this.checkConflicts(agent.id, meetingDetails.start, meetingDetails.end);\n      if (conflicts.length > 0) {\n        return await this.suggestAlternativeTimes(agent.id, meetingDetails);\n      }\n      \n      // 4. Create booking\n      const booking = await this.client.createBooking({\n        agent_id: agent.id,\n        customer_email: customerInfo.email,\n        customer_name: customerInfo.name,\n        meeting_title: meetingDetails.title,\n        meeting_description: meetingDetails.description,\n        scheduled_start: meetingDetails.start,\n        scheduled_end: meetingDetails.end,\n        booking_source: 'email_integration',\n        ai_confidence: meetingDetails.confidence\n      });\n      \n      console.log(`✅ Booking created: ${booking.id}`);\n      return booking;\n      \n    } catch (error) {\n      console.error('❌ Booking creation failed:', error);\n      throw error;\n    }\n  }\n  \n  async extractMeetingDetails(emailContent) {\n    // Call AI endpoint to extract meeting details\n    const response = await this.client.post('/ai/extract-meeting-details', {\n      content: emailContent,\n      language: 'da'\n    });\n    \n    return {\n      title: response.data.title || 'Generelt møde',\n      description: response.data.description,\n      preferredTime: response.data.preferred_time,\n      duration: response.data.duration || 60,\n      topic: response.data.topic,\n      confidence: response.data.confidence\n    };\n  }\n  \n  async findAvailableAgent(preferredTime, topic) {\n    const agents = await this.client.get('/agents', {\n      params: {\n        is_active: true,\n        has_availability: true,\n        expertise: topic\n      }\n    });\n    \n    // Sort by expertise match and availability\n    return agents.data.agents\n      .sort((a, b) => b.expertise_match - a.expertise_match)\n      .find(agent => agent.next_available <= preferredTime);\n  }\n  \n  async checkConflicts(agentId, startTime, endTime) {\n    const response = await this.client.get(`/agents/${agentId}/bookings`, {\n      params: {\n        start_date: startTime.toISOString(),\n        end_date: endTime.toISOString(),\n        status: ['scheduled', 'confirmed']\n      }\n    });\n    \n    return response.data.bookings.filter(booking => {\n      const bookingStart = new Date(booking.scheduled_start);\n      const bookingEnd = new Date(booking.scheduled_end);\n      \n      return (startTime < bookingEnd && endTime > bookingStart);\n    });\n  }\n}\n\n// Usage\nconst bookingManager = new BookingManager(client);\n\n// Auto-create booking from email\napp.post('/webhooks/gmail', async (req, res) => {\n  const emailData = req.body.data;\n  \n  if (emailData.ai_confidence > 0.8 && emailData.contains_booking_request) {\n    const booking = await bookingManager.createBookingFromEmail(\n      emailData,\n      { email: emailData.from, name: emailData.customer_name }\n    );\n    \n    console.log('🚀 Auto-booking created:', booking.id);\n  }\n  \n  res.json({ success: true });\n});\n```\n\n## 🎯 Advanced Use Cases\n\n### 1. Multi-Agent Customer Service\n```javascript\nclass CustomerServiceOrchestrator {\n  constructor(client) {\n    this.client = client;\n  }\n  \n  async routeCustomerInquiry(emailData) {\n    // Classify inquiry type using AI\n    const classification = await this.classifyInquiry(emailData.content);\n    \n    const routingRules = {\n      'technical_support': 'agent_support',\n      'billing_question': 'agent_billing', \n      'sales_inquiry': 'agent_sales',\n      'general_question': 'agent_general'\n    };\n    \n    const targetAgent = routingRules[classification.category] || 'agent_general';\n    \n    // Check agent availability and workload\n    const agent = await this.selectBestAgent(targetAgent, classification.urgency);\n    \n    // Create or update conversation\n    await this.client.post('/conversations', {\n      customer_email: emailData.from,\n      agent_id: agent.id,\n      subject: emailData.subject,\n      classification: classification,\n      priority: this.calculatePriority(classification)\n    });\n    \n    // Auto-respond if appropriate\n    if (classification.confidence > 0.9) {\n      return await this.generateAutoResponse(agent, classification, emailData);\n    }\n  }\n  \n  async selectBestAgent(agentType, urgency) {\n    const agents = await this.client.get(`/agents?role=${agentType}&is_active=true`);\n    \n    // Factor in current workload, availability, and expertise\n    return agents.data.agents\n      .filter(a => urgency === 'high' ? a.handles_urgent : true)\n      .sort((a, b) => a.current_workload - b.current_workload)[0];\n  }\n}\n```\n\n### 2. Real-time Dashboard Integration\n```javascript\n// WebSocket connection for real-time updates\nconst WebSocket = require('ws');\n\nclass AgentlyDashboard {\n  constructor(apiKey) {\n    this.client = new AgentlyClient(apiKey);\n    this.ws = new WebSocket('wss://realtime.agently.dk', {\n      headers: { 'Authorization': `Bearer ${apiKey}` }\n    });\n    \n    this.setupWebSocketHandlers();\n  }\n  \n  setupWebSocketHandlers() {\n    this.ws.on('message', (data) => {\n      const event = JSON.parse(data);\n      \n      switch (event.type) {\n        case 'booking.created':\n          this.updateBookingsList(event.data);\n          this.showNotification(`New booking: ${event.data.meeting_title}`);\n          break;\n          \n        case 'conversation.manual_takeover_requested':\n          this.alertAgent(event.data);\n          break;\n          \n        case 'agent.performance_alert':\n          this.showPerformanceAlert(event.data);\n          break;\n      }\n    });\n    \n    this.ws.on('error', (error) => {\n      console.error('WebSocket error:', error);\n      this.reconnectWebSocket();\n    });\n  }\n  \n  async loadDashboardData() {\n    const [agents, bookings, conversations, metrics] = await Promise.all([\n      this.client.get('/agents?include_metrics=true'),\n      this.client.get('/bookings?limit=50&sort=created_at:desc'),  \n      this.client.get('/conversations?status=active&limit=20'),\n      this.client.get('/analytics/dashboard')\n    ]);\n    \n    return {\n      agents: agents.data.agents,\n      recentBookings: bookings.data.bookings,\n      activeConversations: conversations.data.conversations,\n      metrics: metrics.data\n    };\n  }\n  \n  updateBookingsList(newBooking) {\n    // Update UI with new booking\n    const bookingElement = this.createBookingElement(newBooking);\n    document.querySelector('#recent-bookings').prepend(bookingElement);\n    \n    // Animate in\n    bookingElement.classList.add('animate-slide-in');\n  }\n}\n```\n\n### 3. Email Filter Machine Learning Pipeline\n```javascript\nclass SmartEmailFilter {\n  constructor(client) {\n    this.client = client;\n  }\n  \n  async setupLearningPipeline() {\n    // Create smart filters based on historical data\n    const filterRules = await this.analyzePastEmails();\n    \n    for (const rule of filterRules) {\n      await this.client.post('/email-filters', {\n        name: rule.name,\n        criteria: rule.criteria,\n        action: rule.action,\n        confidence_threshold: rule.confidence,\n        auto_learn: true,\n        description: `Auto-generated filter based on ${rule.sample_size} similar emails`\n      });\n    }\n  }\n  \n  async trainOnUserFeedback() {\n    // Get recent feedback\n    const feedback = await this.client.get('/email-filters/feedback?days=7');\n    \n    // Retrain ML models\n    const trainingData = feedback.data.feedback.map(f => ({\n      email_features: f.email_features,\n      user_decision: f.user_decision,\n      confidence: f.confidence\n    }));\n    \n    const response = await this.client.post('/email-filters/train', {\n      training_data: trainingData,\n      model_version: 'v2.0'\n    });\n    \n    console.log(`Model trained with ${trainingData.length} samples. Accuracy: ${response.data.accuracy}`);\n  }\n  \n  async analyzePastEmails() {\n    const pastEmails = await this.client.get('/conversations/emails', {\n      params: {\n        days: 30,\n        include_actions: true,\n        min_confidence: 0.8\n      }\n    });\n    \n    // Group by patterns and generate rules\n    const patterns = this.findEmailPatterns(pastEmails.data.emails);\n    \n    return patterns.map(pattern => ({\n      name: `Auto-filter: ${pattern.description}`,\n      criteria: {\n        sender_domain: pattern.sender_patterns,\n        subject_keywords: pattern.subject_patterns,\n        content_signals: pattern.content_patterns\n      },\n      action: pattern.most_common_action,\n      confidence: pattern.confidence,\n      sample_size: pattern.sample_size\n    }));\n  }\n}\n```\n\n## 🔧 Error Handling & Best Practices\n\n### Comprehensive Error Handling\n```javascript\nclass RobustAgentlyClient extends AgentlyClient {\n  constructor(apiKey, options = {}) {\n    super(apiKey);\n    this.retryAttempts = options.retryAttempts || 3;\n    this.retryDelay = options.retryDelay || 1000;\n    this.circuitBreaker = new CircuitBreaker(options.circuitBreaker);\n  }\n  \n  async request(method, endpoint, data = null, options = {}) {\n    let attempt = 0;\n    \n    while (attempt < this.retryAttempts) {\n      try {\n        // Circuit breaker check\n        if (this.circuitBreaker.isOpen()) {\n          throw new Error('Circuit breaker is open');\n        }\n        \n        const response = await this.client[method](endpoint, data, options);\n        this.circuitBreaker.recordSuccess();\n        return response;\n        \n      } catch (error) {\n        attempt++;\n        this.circuitBreaker.recordFailure();\n        \n        // Don't retry client errors (4xx)\n        if (error.response?.status >= 400 && error.response?.status < 500) {\n          throw this.createAgentlyError(error);\n        }\n        \n        // Retry server errors (5xx) and network errors\n        if (attempt < this.retryAttempts) {\n          const delay = this.calculateBackoffDelay(attempt);\n          console.log(`Request failed, retrying in ${delay}ms (attempt ${attempt}/${this.retryAttempts})`);\n          await this.sleep(delay);\n          continue;\n        }\n        \n        throw this.createAgentlyError(error);\n      }\n    }\n  }\n  \n  createAgentlyError(error) {\n    const agentlyError = new AgentlyError(\n      error.response?.data?.message || error.message,\n      error.response?.status,\n      error.response?.data?.error_code,\n      error.response?.data\n    );\n    \n    // Add helpful context\n    switch (error.response?.status) {\n      case 401:\n        agentlyError.suggestion = 'Check your API key is valid and not expired';\n        break;\n      case 403:\n        agentlyError.suggestion = 'Your API key may not have the required permissions';\n        break;\n      case 429:\n        agentlyError.suggestion = `Rate limit exceeded. Retry after ${error.response.headers['retry-after']} seconds`;\n        break;\n      case 422:\n        agentlyError.suggestion = 'Validation failed. Check the request data format';\n        break;\n    }\n    \n    return agentlyError;\n  }\n  \n  calculateBackoffDelay(attempt) {\n    // Exponential backoff with jitter\n    const baseDelay = this.retryDelay * Math.pow(2, attempt - 1);\n    const jitter = Math.random() * 0.1 * baseDelay;\n    return Math.min(baseDelay + jitter, 30000); // Max 30 seconds\n  }\n  \n  sleep(ms) {\n    return new Promise(resolve => setTimeout(resolve, ms));\n  }\n}\n\nclass AgentlyError extends Error {\n  constructor(message, statusCode, errorCode, data) {\n    super(message);\n    this.name = 'AgentlyError';\n    this.statusCode = statusCode;\n    this.errorCode = errorCode;\n    this.data = data;\n  }\n}\n```\n\n### Production Monitoring\n```javascript\nconst { createLogger, transports, format } = require('winston');\n\n// Setup structured logging\nconst logger = createLogger({\n  format: format.combine(\n    format.timestamp(),\n    format.errors({ stack: true }),\n    format.json()\n  ),\n  transports: [\n    new transports.File({ filename: 'agently-integration.log' }),\n    new transports.Console({ format: format.simple() })\n  ]\n});\n\n// Performance monitoring\nclass AgentlyMonitor {\n  constructor(client) {\n    this.client = client;\n    this.metrics = {\n      requests: 0,\n      errors: 0,\n      response_times: []\n    };\n  }\n  \n  async monitorRequest(endpoint, operation) {\n    const startTime = Date.now();\n    this.metrics.requests++;\n    \n    try {\n      const result = await operation();\n      const responseTime = Date.now() - startTime;\n      \n      this.metrics.response_times.push(responseTime);\n      \n      logger.info('API request successful', {\n        endpoint,\n        response_time: responseTime,\n        timestamp: new Date().toISOString()\n      });\n      \n      return result;\n    } catch (error) {\n      this.metrics.errors++;\n      \n      logger.error('API request failed', {\n        endpoint,\n        error: error.message,\n        status_code: error.statusCode,\n        response_time: Date.now() - startTime,\n        timestamp: new Date().toISOString()\n      });\n      \n      throw error;\n    }\n  }\n  \n  getHealthMetrics() {\n    const avgResponseTime = this.metrics.response_times.reduce((a, b) => a + b, 0) / this.metrics.response_times.length;\n    \n    return {\n      total_requests: this.metrics.requests,\n      total_errors: this.metrics.errors,\n      error_rate: this.metrics.errors / this.metrics.requests,\n      avg_response_time: avgResponseTime,\n      health_status: this.metrics.errors / this.metrics.requests < 0.05 ? 'healthy' : 'degraded'\n    };\n  }\n}\n\n// Usage\nconst monitor = new AgentlyMonitor(client);\n\n// Wrap API calls with monitoring\nconst createBooking = async (bookingData) => {\n  return monitor.monitorRequest('POST /bookings', async () => {\n    return client.createBooking(bookingData);\n  });\n};\n```\n\n## 📚 Testing & Development\n\n### Integration Tests\n```javascript\nconst { describe, test, expect, beforeAll, afterAll } = require('@jest/globals');\n\ndescribe('Agently API Integration', () => {\n  let client;\n  let testAgent;\n  \n  beforeAll(async () => {\n    client = new AgentlyClient(process.env.AGENTLY_TEST_API_KEY);\n    \n    // Create test agent\n    testAgent = await client.createAgent({\n      name: 'Test Agent',\n      role: 'general',\n      personality: 'Helpful test assistant'\n    });\n  });\n  \n  afterAll(async () => {\n    // Cleanup test data\n    if (testAgent) {\n      await client.delete(`/agents/${testAgent.id}`);\n    }\n  });\n  \n  test('should create and retrieve agent', async () => {\n    expect(testAgent).toBeDefined();\n    expect(testAgent.name).toBe('Test Agent');\n    \n    const retrieved = await client.get(`/agents/${testAgent.id}`);\n    expect(retrieved.data.id).toBe(testAgent.id);\n  });\n  \n  test('should handle booking creation workflow', async () => {\n    const bookingData = {\n      agent_id: testAgent.id,\n      customer_email: 'test@example.com',\n      customer_name: 'Test Customer',\n      meeting_title: 'Test Meeting',\n      scheduled_start: new Date(Date.now() + 24 * 60 * 60 * 1000).toISOString(),\n      scheduled_end: new Date(Date.now() + 25 * 60 * 60 * 1000).toISOString(),\n      booking_source: 'api_test'\n    };\n    \n    const booking = await client.createBooking(bookingData);\n    expect(booking.id).toBeDefined();\n    expect(booking.status).toBe('scheduled');\n    \n    // Cleanup\n    await client.delete(`/bookings/${booking.id}`);\n  });\n  \n  test('should handle rate limiting gracefully', async () => {\n    const requests = Array(20).fill().map(() => \n      client.get(`/agents/${testAgent.id}`)\n    );\n    \n    // Should not throw on rate limiting\n    const results = await Promise.allSettled(requests);\n    const successful = results.filter(r => r.status === 'fulfilled');\n    \n    expect(successful.length).toBeGreaterThan(0);\n  });\n});\n```\n\nDeze comprehensive integration guide giver udviklere alt hvad de behøver for at integrere Agently AI platformen i deres applikationer med best practices, fejlhåndtering og real-world eksempler."}},"tags":[{"name":"System","description":"System health og monitoring"},{"name":"Agents","description":"AI agent management"},{"name":"Bookings","description":"Booking management med automatisk konflikt detektion og AI-powered auto-confirmation"},{"name":"Calendar","description":"Kalender events, tilgængelighed og agent scheduling"},{"name":"AI","description":"AI-powered funktionaliteter inklusiv intelligent booking analyse og confidence scoring"},{"name":"Analytics","description":"Statistikker og performance metrics for AI agents og booking system"},{"name":"API Keys","description":"API key management og authentication"},{"name":"Webhooks","description":"Real-time webhook notifikationer til externe systemer"}]}