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

LevelDescriptionDefault Channels
criticalSystem down, immediate action requiredSMS, Voice Call, Email
warningPotential issue, should investigateSMS, Email
infoInformational, no action neededEmail 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.

Services vs Webhooks Services use integration keys and the Events API β€” ideal for structured event-driven alerting (compatible with OpsGenie format). Webhooks use unique URLs β€” ideal for quick integration with any tool that can send HTTP POST requests. Both deliver alerts through the same 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:

POST https://api.monoduty.com/api/v1/events?integration_key=YOUR_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

FieldTypeRequiredDescription
messagestringYesAlert message / title
prioritystringNoP1 (Critical) to P5 (Info). Default: P3
aliasstringNoUnique identifier for deduplication
descriptionstringNoDetailed description of the alert
tagsarrayNoArray of string tags for categorization
entitystringNoThe entity/resource this alert relates to
sourcestringNoSource system (e.g., "prometheus", "grafana")
detailsobjectNoAdditional key-value details
actionsarrayNoAvailable actions for the alert

Priority Levels

PrioritySeverityDefault Channels
P1CriticalVoice Call, SMS, Email, Push, Slack, Discord
P2HighSMS, Email, Push, Slack, Discord
P3ModerateEmail, Push, Slack, Discord
P4LowEmail, Slack
P5InformationalEmail 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

  1. Navigate to Dashboard β†’ Services
  2. Click on a service (or create a new one)
  3. Copy the Integration Key from the service detail page
  4. Use this key as a query parameter: ?integration_key=YOUR_KEY
Keep Integration Keys Secret Integration keys authenticate events for your service. Never expose them in client-side code or public repositories.

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.

How It Works When you exceed a rate limit, MonoDuty returns a 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:

LayerScopePurpose
Endpoint-SpecificPer IP or per user, per endpointGranular limits tailored to each endpoint's expected usage pattern
Advanced AuthPer IP + per usernameBrute-force protection for login and authentication endpoints
Plan-BasedPer account / subscriptionEnforces 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"
}
Best Practice Implement exponential backoff in your integrations. When you receive a 429, wait for the 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.

EndpointLimitWindowKey
/api/* (general)500 requests15 minutesIP
/login, /api/auth/login20 requests1 hourIP
/webhook/*, /api/v1/events300 requests5 minutesIP
/signup, /register10 requests1 hourIP
/api/incidents (create)100 requests15 minutesUser
/api/reports/generate10 requests15 minutesUser
/api/search200 requests15 minutesUser
/forgot-password, /reset-password5 requests1 hourIP
/api/account/export-data3 requests1 hourUser
/api/billing30 requests15 minutesUser
/api/mobile300 requests15 minutesIP
/api/auth/refresh30 requests15 minutesIP
/admin, /api/admin200 requests15 minutesUser
IP vs User-based Limits Endpoints marked with IP key are limited per source IP address. Endpoints marked with User key are limited per authenticated user (falling back to IP if not logged in). User-based limits are more fair for shared networks and office environments.

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.

DimensionLimitWindowPurpose
Per IP50 attempts1 hourPrevents distributed attacks from a single source
Per Username10 attempts1 hourPrevents 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
Fail-Open Policy If the rate limiting system encounters an internal error (e.g., Redis connection issue), requests are allowed through rather than blocked. This ensures that a rate limiting infrastructure failure never prevents legitimate users from logging in.

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:

PlanWebhooks / HourEvents API / Hour
Free1010
Starter5050
Pro100100
Business500500
EnterpriseCustomCustom
Plan Limits vs Endpoint Limits Plan-based limits and endpoint rate limits are enforced independently. You must stay within both. For example, even if your Pro plan allows 100 webhooks/hour, you still cannot exceed 300 requests per 5 minutes to the webhook endpoint.

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.

Why Deduplication Matters Without deduplication, a single infrastructure issue could generate dozens or hundreds of duplicate incidents, causing alert fatigue and making it harder to identify real problems. MonoDuty's dedup engine ensures each unique issue maps to exactly one incident.

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_at timestamp
  • 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.

βœ“
Best Practice Always include an 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 alias or external_incident_id is 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.

Availability Semantic deduplication requires an AI-enabled plan and must be explicitly enabled via the AI_SMART_DEDUP_ENABLED setting. It is disabled by default.

How Semantic Matching Works

  1. MonoDuty generates an AI embedding (vector representation) of the new incident's title and description
  2. It compares this embedding against recent open incidents within the same service and group
  3. If the cosine similarity between any existing incident and the new event exceeds the threshold (default: 85%), the events are considered duplicates
  4. The existing incident is updated with the new occurrence data

Configuration

ParameterDefaultDescription
threshold0.85 (85%)Minimum cosine similarity score to consider two incidents as duplicates
timeWindowHours24 hoursOnly compare against incidents created within this time window
limit20Maximum 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:

StepMethodSpeedWhen Used
1Exact Match~1msAlways (if alias/external_id present)
2Semantic Match~50-200msOnly if exact match not found and AI is enabled
βœ“
Monitoring Deduplication You can track deduplication effectiveness per service through the dashboard. Metrics include total incidents vs unique incidents, average occurrence count per incident, and dedup hit rate over time.