Getting started
MonoDuty Core Concepts
Learn how MonoDuty webhooks, services, Events API integration keys, rate limits, and deduplication work together.
Core Concepts
Webhooks
A webhook is a unique URL endpoint that accepts HTTP POST requests. When a request is received, MonoDuty processes the payload and sends alerts to your configured notification channels.
Notification Channels
MonoDuty supports multiple notification channels:
- SMS - Text messages with global delivery
- Email - Rich HTML emails with full context
- Voice Calls - Automated phone calls for critical alerts
- Push Notifications - Mobile app notifications (iOS & Android)
Severity Levels
| Level | Description | Default Channels |
|---|---|---|
critical | System down, immediate action required | SMS, Voice Call, Email |
warning | Potential issue, should investigate | SMS, Email |
info | Informational, no action needed | Email only |
Services & Events API
Services are the core building blocks in MonoDuty. Each service represents a system, application, or component you want to monitor. Services receive events through a unique integration key and route alerts to the right people through configured notification channels.
Key Features
- Integration Keys β Each service gets a unique key for sending events
- OpsGenie-Compatible β Natively understands OpsGenie Alert API v2 format
- Priority Mapping β P1-P5 priority levels with automatic severity mapping
- Deduplication β Use aliases to prevent duplicate alerts
- Multi-Channel Routing β Route alerts to Email, SMS, Voice, Slack, Discord, Push
- Escalation Policies β Configure time-based escalation chains
- Auto-Incidents β Automatically create and manage incidents from events
Sending Events
The Events API is the primary way to send alerts to a service. Send a POST request with your integration key:
Basic Event Example
curl -X POST 'https://api.monoduty.com/api/v1/events?integration_key=YOUR_INTEGRATION_KEY' \
-H 'Content-Type: application/json' \
-d '{
"message": "CPU usage exceeded 90% on prod-server-01",
"priority": "P2",
"alias": "cpu-alert-prod-001",
"description": "CPU has been above 90% for 5 minutes",
"tags": ["production", "cpu", "server"],
"entity": "prod-server-01",
"source": "prometheus"
}'Event Fields
| Field | Type | Required | Description |
|---|---|---|---|
message | string | Yes | Alert message / title |
priority | string | No | P1 (Critical) to P5 (Info). Default: P3 |
alias | string | No | Unique identifier for deduplication |
description | string | No | Detailed description of the alert |
tags | array | No | Array of string tags for categorization |
entity | string | No | The entity/resource this alert relates to |
source | string | No | Source system (e.g., "prometheus", "grafana") |
details | object | No | Additional key-value details |
actions | array | No | Available actions for the alert |
Priority Levels
| Priority | Severity | Default Channels |
|---|---|---|
P1 | Critical | Voice Call, SMS, Email, Push, Slack, Discord |
P2 | High | SMS, Email, Push, Slack, Discord |
P3 | Moderate | Email, Push, Slack, Discord |
P4 | Low | Email, Slack |
P5 | Informational | Email only |
Integration Keys
Each service has a unique integration key used to authenticate events. You can find your integration key in the service detail page.
Getting Your Integration Key
- Navigate to Dashboard β Services
- Click on a service (or create a new one)
- Copy the Integration Key from the service detail page
- Use this key as a query parameter:
?integration_key=YOUR_KEY
Rate Limiting
MonoDuty applies rate limiting at multiple layers to protect the platform and ensure fair usage across all accounts. Rate limits prevent abuse, control costs, and maintain service reliability for everyone.
429 Too Many Requests response with a retryAfter field indicating how many seconds to wait before retrying. Standard rate limit headers (X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset) are included in every response. Rate Limit Layers
MonoDuty enforces rate limits at three distinct layers:
| Layer | Scope | Purpose |
|---|---|---|
| Endpoint-Specific | Per IP or per user, per endpoint | Granular limits tailored to each endpoint's expected usage pattern |
| Advanced Auth | Per IP + per username | Brute-force protection for login and authentication endpoints |
| Plan-Based | Per account / subscription | Enforces usage limits based on your subscription plan |
429 Response Format
{
"error": "Rate limit exceeded",
"message": "Too many requests, please try again later.",
"retryAfter": 900,
"requestId": "req_abc123"
}retryAfter duration before retrying. Repeatedly hitting rate limits may result in longer cooldown periods. Endpoint Rate Limits
Each API endpoint category has its own rate limit window and maximum request count. Requests to health checks, static assets, and internal IPs (in development) are automatically excluded.
| Endpoint | Limit | Window | Key |
|---|---|---|---|
/api/* (general) | 500 requests | 15 minutes | IP |
/login, /api/auth/login | 20 requests | 1 hour | IP |
/webhook/*, /api/v1/events | 300 requests | 5 minutes | IP |
/signup, /register | 10 requests | 1 hour | IP |
/api/incidents (create) | 100 requests | 15 minutes | User |
/api/reports/generate | 10 requests | 15 minutes | User |
/api/search | 200 requests | 15 minutes | User |
/forgot-password, /reset-password | 5 requests | 1 hour | IP |
/api/account/export-data | 3 requests | 1 hour | User |
/api/billing | 30 requests | 15 minutes | User |
/api/mobile | 300 requests | 15 minutes | IP |
/api/auth/refresh | 30 requests | 15 minutes | IP |
/admin, /api/admin | 200 requests | 15 minutes | User |
Webhook Rate Limits
Webhook ingestion endpoints have an additional feature: successful requests are not counted against the limit. This means the 300/5min limit only applies to failed or malformed requests, so legitimate webhook traffic is rarely affected.
Advanced Authentication Rate Limiting
Login and authentication endpoints have an additional layer of protection that combines IP-based and user-based rate limiting to prevent brute-force attacks.
| Dimension | Limit | Window | Purpose |
|---|---|---|---|
| Per IP | 50 attempts | 1 hour | Prevents distributed attacks from a single source |
| Per Username | 10 attempts | 1 hour | Prevents targeted attacks on a specific account |
Both dimensions are checked simultaneously. If either limit is exceeded, the request is rejected with a 429 response.
How It Works
Request arrives at /login βββ Check IP limit (50/hour) β βββ Exceeded? β 429 "Too many login attempts from this IP" βββ Check Username limit (10/hour) β βββ Exceeded? β 429 "Too many login attempts for this account" βββ Both passed β Continue to authentication
Plan-Based Webhook Limits
In addition to endpoint rate limits, webhook ingestion is also subject to your subscription plan limits. Each plan defines how many webhook requests you can send per hour:
| Plan | Webhooks / Hour | Events API / Hour |
|---|---|---|
Free | 10 | 10 |
Starter | 50 | 50 |
Pro | 100 | 100 |
Business | 500 | 500 |
Enterprise | Custom | Custom |
Deduplication
MonoDuty automatically deduplicates incoming events and alerts to prevent duplicate incidents from flooding your team. When multiple identical alerts arrive (e.g., a monitoring tool firing repeatedly for the same issue), MonoDuty groups them into a single incident and tracks occurrence count.
How It Works
MonoDuty uses a two-phase deduplication strategy:
Incoming Event β βββ Phase 1: Exact Match β βββ Is there an OPEN incident with the same β external_incident_id + service_id? β βββ YES β Update existing incident (increment occurrence count) β βββ NO β Continue to Phase 2 β βββ Phase 2: Semantic Match (if AI enabled) β βββ Are there OPEN incidents with semantically β similar title/description? β βββ YES (similarity β₯ 85%) β Update existing incident β βββ NO β Create new incident β βββ No Match β Create new incident
Exact Match Deduplication
The primary deduplication method uses exact matching on two fields:
external_incident_idβ A unique identifier from your monitoring tool (e.g., Sentry issue ID, Prometheus alert fingerprint)service_idβ The MonoDuty service receiving the event
If an OPEN or IN_PROGRESS incident already exists with the same combination, MonoDuty updates the existing incident instead of creating a new one:
- Increments the
occurrence_count - Updates
last_seen_attimestamp - Appends the new occurrence to the incident's metadata history (last 10 kept)
Events API Deduplication
When using the Events API, the alias field serves as the deduplication key:
{
"message": "CPU usage above 90% on prod-server-01",
"priority": "P2",
"alias": "cpu-alert-prod-001",
"source": "prometheus"
}If you send another event with the same alias to the same service while the original incident is still open, MonoDuty will update the existing incident rather than creating a duplicate.
alias (Events API) or external_incident_id (webhooks) in your alerts. Use a stable, unique identifier for each distinct problem β for example, cpu-alert-{hostname} or sentry:{issue_id}. This ensures accurate deduplication. Safe Defaults
MonoDuty's dedup engine is designed with a fail-safe approach:
- If no
aliasorexternal_incident_idis provided, a new incident is always created - If the deduplication check fails (e.g., database error), a new incident is created rather than silently dropping the alert
- The rationale: a duplicate incident is less risky than a lost incident
Semantic Deduplication (AI-Powered)
When exact matching doesn't find a duplicate (e.g., the alert doesn't include an alias), MonoDuty can optionally use AI-powered semantic similarity to detect incidents that describe the same underlying problem in different words.
AI_SMART_DEDUP_ENABLED setting. It is disabled by default. How Semantic Matching Works
- MonoDuty generates an AI embedding (vector representation) of the new incident's title and description
- It compares this embedding against recent open incidents within the same service and group
- If the cosine similarity between any existing incident and the new event exceeds the threshold (default: 85%), the events are considered duplicates
- The existing incident is updated with the new occurrence data
Configuration
| Parameter | Default | Description |
|---|---|---|
threshold | 0.85 (85%) | Minimum cosine similarity score to consider two incidents as duplicates |
timeWindowHours | 24 hours | Only compare against incidents created within this time window |
limit | 20 | Maximum number of recent incidents to compare against |
Example: Semantic Match
These two alerts would be matched as duplicates by the semantic engine, even though the wording differs:
Alert 1: "Database connection pool exhausted on prod-db-01" Alert 2: "MySQL connection limit reached β prod-db-01 cannot accept new connections" Cosine Similarity: 0.91 (above 0.85 threshold) β DUPLICATE
Combined Deduplication Flow
MonoDuty always tries exact match first (fastest), then falls back to semantic matching:
| Step | Method | Speed | When Used |
|---|---|---|---|
| 1 | Exact Match | ~1ms | Always (if alias/external_id present) |
| 2 | Semantic Match | ~50-200ms | Only if exact match not found and AI is enabled |