Skip to content

API Endpoints Reference

This page provides detailed documentation for all 9n9s REST API endpoints. All API requests must include authentication headers and follow RESTful conventions.

Dashboard First: Most users should start with the web interface for setup and configuration. Use the API for automation, integrations, and programmatic management after you’re familiar with 9n9s concepts.

All API requests are made to: https://api.9n9s.com/v1

Include your API key in the Authorization header for all requests:

Authorization: Bearer your_api_key_here

List all organizations you have access to.

GET /organizations

Response:

{
"data": [
{
"id": "org_1234567890",
"name": "Acme Corp",
"slug": "acme-corp",
"created_at": "2024-01-15T10:30:00Z",
"updated_at": "2024-01-15T10:30:00Z",
"role": "admin"
}
],
"pagination": {
"page": 1,
"per_page": 25,
"total": 1
}
}

Retrieve details about a specific organization.

GET /organizations/{organization_id}

Response:

{
"data": {
"id": "org_1234567890",
"name": "Acme Corp",
"slug": "acme-corp",
"created_at": "2024-01-15T10:30:00Z",
"updated_at": "2024-01-15T10:30:00Z",
"role": "admin",
"members_count": 5,
"projects_count": 3,
"monitors_count": 25
}
}

Update organization details.

PATCH /organizations/{organization_id}

Request Body:

{
"name": "New Organization Name"
}

Response:

{
"data": {
"id": "org_1234567890",
"name": "New Organization Name",
"slug": "acme-corp",
"updated_at": "2024-01-15T14:30:00Z"
}
}

List all projects in an organization.

GET /organizations/{organization_id}/projects

Query Parameters:

  • page (integer): Page number for pagination (default: 1)
  • per_page (integer): Items per page (default: 25, max: 100)
  • search (string): Search projects by name or slug

Response:

{
"data": [
{
"id": "proj_1234567890",
"name": "Frontend Application",
"slug": "frontend-app",
"organization_id": "org_1234567890",
"created_at": "2024-01-15T10:30:00Z",
"updated_at": "2024-01-15T10:30:00Z",
"monitors_count": 12
}
],
"pagination": {
"page": 1,
"per_page": 25,
"total": 3
}
}

Create a new project within an organization.

POST /organizations/{organization_id}/projects

Request Body:

{
"name": "My New Project",
"slug": "my-new-project"
}

Response:

{
"data": {
"id": "proj_1234567890",
"name": "My New Project",
"slug": "my-new-project",
"organization_id": "org_1234567890",
"created_at": "2024-01-15T14:30:00Z",
"updated_at": "2024-01-15T14:30:00Z",
"monitors_count": 0
}
}

Retrieve details about a specific project.

GET /projects/{project_id}

Response:

{
"data": {
"id": "proj_1234567890",
"name": "Frontend Application",
"slug": "frontend-app",
"organization_id": "org_1234567890",
"created_at": "2024-01-15T10:30:00Z",
"updated_at": "2024-01-15T10:30:00Z",
"monitors_count": 12,
"uptime_monitors_count": 8,
"heartbeat_monitors_count": 4
}
}

Update project details.

PATCH /projects/{project_id}

Request Body:

{
"name": "Updated Project Name"
}

Delete a project and all its monitors.

DELETE /projects/{project_id}

Response:

{
"message": "Project deleted successfully"
}

List all monitors in a project.

GET /projects/{project_id}/monitors

Query Parameters:

  • type (string): Filter by monitor type (heartbeat, uptime)
  • status (string): Filter by status (up, down, degraded, paused)
  • tags (string): Filter by tags (comma-separated)
  • search (string): Search by monitor name
  • page (integer): Page number
  • per_page (integer): Items per page

Response:

{
"data": [
{
"id": "mon_1234567890",
"name": "API Health Check",
"type": "heartbeat",
"status": "up",
"project_id": "proj_1234567890",
"created_at": "2024-01-15T10:30:00Z",
"updated_at": "2024-01-15T12:45:00Z",
"last_pulse_at": "2024-01-15T14:25:00Z",
"tags": ["api", "production"],
"schedule": "*/5 * * * *",
"grace_period": "300",
"timezone": "UTC"
}
],
"pagination": {
"page": 1,
"per_page": 25,
"total": 12
}
}

Create a new heartbeat monitor.

POST /projects/{project_id}/monitors/heartbeat

Request Body:

{
"name": "Daily Backup Job",
"schedule": "0 2 * * *",
"grace_period": "3600",
"timezone": "America/New_York",
"tags": ["backup", "production"],
"expected_runtime": {
"min": 60,
"max": 3600
}
}

Response:

{
"data": {
"id": "mon_1234567890",
"name": "Daily Backup Job",
"type": "heartbeat",
"status": "paused",
"project_id": "proj_1234567890",
"pulse_url": "https://pulse.9n9s.com/uuid-here",
"uuid": "uuid-here",
"schedule": "0 2 * * *",
"grace_period": "3600",
"timezone": "America/New_York",
"tags": ["backup", "production"],
"expected_runtime": {
"min": 60,
"max": 3600
},
"created_at": "2024-01-15T14:30:00Z",
"updated_at": "2024-01-15T14:30:00Z"
}
}

Create a new uptime monitor.

POST /projects/{project_id}/monitors/uptime

Request Body:

{
"name": "Homepage Check",
"target": "https://example.com",
"frequency": "60",
"timeout": "30",
"tags": ["website", "production"],
"assertions": [
{
"type": "status_code",
"operator": "equals",
"value": "200"
},
{
"type": "response_time",
"operator": "less_than",
"value": "2000"
}
],
"headers": {
"User-Agent": "9n9s-Monitor/1.0"
}
}

Response:

{
"data": {
"id": "mon_0987654321",
"name": "Homepage Check",
"type": "uptime",
"status": "paused",
"project_id": "proj_1234567890",
"target": "https://example.com",
"frequency": "60",
"timeout": "30",
"tags": ["website", "production"],
"assertions": [
{
"type": "status_code",
"operator": "equals",
"value": "200"
}
],
"created_at": "2024-01-15T14:30:00Z",
"updated_at": "2024-01-15T14:30:00Z"
}
}

Retrieve details about a specific monitor.

GET /monitors/{monitor_id}

Response:

{
"data": {
"id": "mon_1234567890",
"name": "API Health Check",
"type": "heartbeat",
"status": "up",
"project_id": "proj_1234567890",
"pulse_url": "https://pulse.9n9s.com/uuid-here",
"uuid": "uuid-here",
"schedule": "*/5 * * * *",
"grace_period": "300",
"timezone": "UTC",
"tags": ["api", "production"],
"created_at": "2024-01-15T10:30:00Z",
"updated_at": "2024-01-15T12:45:00Z",
"last_pulse_at": "2024-01-15T14:25:00Z",
"stats": {
"uptime_percentage": 99.5,
"total_pulses": 1440,
"failed_pulses": 7,
"avg_response_time": 125
}
}
}

Update monitor configuration.

PATCH /monitors/{monitor_id}

Request Body:

{
"name": "Updated Monitor Name",
"tags": ["api", "production", "critical"],
"grace_period": "600"
}

Delete a monitor.

DELETE /monitors/{monitor_id}

Response:

{
"message": "Monitor deleted successfully"
}

Pause or resume a monitor.

POST /monitors/{monitor_id}/pause
POST /monitors/{monitor_id}/resume

Response:

{
"data": {
"id": "mon_1234567890",
"status": "paused",
"updated_at": "2024-01-15T14:30:00Z"
}
}

List incidents for a monitor or project.

GET /monitors/{monitor_id}/incidents
GET /projects/{project_id}/incidents

Query Parameters:

  • status (string): Filter by status (open, resolved)
  • severity (string): Filter by severity (critical, warning, info)
  • since (string): ISO 8601 timestamp for incidents since
  • until (string): ISO 8601 timestamp for incidents until
  • page (integer): Page number
  • per_page (integer): Items per page

Response:

{
"data": [
{
"id": "inc_1234567890",
"monitor_id": "mon_1234567890",
"status": "resolved",
"severity": "critical",
"started_at": "2024-01-15T12:00:00Z",
"resolved_at": "2024-01-15T12:15:00Z",
"duration": "15m",
"description": "Monitor was DOWN",
"root_cause": "Database connection timeout"
}
],
"pagination": {
"page": 1,
"per_page": 25,
"total": 5
}
}

Retrieve details about a specific incident.

GET /incidents/{incident_id}

Response:

{
"data": {
"id": "inc_1234567890",
"monitor_id": "mon_1234567890",
"monitor_name": "API Health Check",
"status": "resolved",
"severity": "critical",
"started_at": "2024-01-15T12:00:00Z",
"resolved_at": "2024-01-15T12:15:00Z",
"duration": "15m",
"description": "Monitor was DOWN",
"root_cause": "Database connection timeout",
"timeline": [
{
"timestamp": "2024-01-15T12:00:00Z",
"event": "incident_started",
"description": "Monitor transitioned to DOWN"
},
{
"timestamp": "2024-01-15T12:05:00Z",
"event": "notification_sent",
"description": "Alert sent to Slack channel"
},
{
"timestamp": "2024-01-15T12:15:00Z",
"event": "incident_resolved",
"description": "Monitor transitioned to UP"
}
]
}
}

List alert rules for a project.

GET /projects/{project_id}/alert-rules

Response:

{
"data": [
{
"id": "rule_1234567890",
"name": "Critical Production Alerts",
"project_id": "proj_1234567890",
"enabled": true,
"conditions": {
"monitor_status": "down",
"tags": ["production"],
"duration": "300"
},
"actions": {
"notification_channels": ["chan_1234567890", "chan_0987654321"],
"deduplication_window": "3600"
},
"created_at": "2024-01-15T10:30:00Z",
"updated_at": "2024-01-15T10:30:00Z"
}
]
}

Create a new alert rule.

POST /projects/{project_id}/alert-rules

Request Body:

{
"name": "Database Alerts",
"enabled": true,
"conditions": {
"monitor_status": "down",
"tags": ["database"],
"duration": "600"
},
"actions": {
"notification_channels": ["chan_1234567890"],
"deduplication_window": "1800"
}
}

List notification channels for an organization.

GET /organizations/{organization_id}/notification-channels

Response:

{
"data": [
{
"id": "chan_1234567890",
"name": "Slack Alerts",
"type": "slack",
"organization_id": "org_1234567890",
"enabled": true,
"configuration": {
"webhook_url": "https://hooks.slack.com/...",
"channel": "#alerts"
},
"created_at": "2024-01-15T10:30:00Z",
"updated_at": "2024-01-15T10:30:00Z"
}
]
}

Create a new notification channel.

POST /organizations/{organization_id}/notification-channels

Request Body (Slack Example):

{
"name": "Team Slack",
"type": "slack",
"configuration": {
"webhook_url": "https://hooks.slack.com/services/...",
"channel": "#monitoring"
}
}

Request Body (Email Example):

{
"name": "Admin Emails",
"type": "email",
"configuration": {
}
}

Send a test notification to verify channel configuration.

POST /notification-channels/{channel_id}/test

Response:

{
"message": "Test notification sent successfully",
"delivered_at": "2024-01-15T14:30:00Z"
}

Send a pulse signal to a heartbeat monitor.

GET https://pulse.9n9s.com/{uuid}
POST https://pulse.9n9s.com/{uuid}

Optional endpoints:

  • /{uuid}/start - Signal job start
  • /{uuid}/fail - Signal job failure
  • /{uuid}/{exit_code} - Signal with exit code

Response:

{
"status": "ok",
"received_at": "2024-01-15T14:30:00Z"
}

All API endpoints return consistent error responses:

{
"error": {
"code": "RESOURCE_NOT_FOUND",
"message": "The requested monitor was not found",
"details": {
"monitor_id": "mon_invalid"
}
}
}
  • 400 BAD_REQUEST - Invalid request parameters
  • 401 UNAUTHORIZED - Invalid or missing API key
  • 403 FORBIDDEN - Insufficient permissions
  • 404 NOT_FOUND - Resource not found
  • 422 VALIDATION_ERROR - Request validation failed
  • 429 RATE_LIMITED - Too many requests
  • 500 INTERNAL_ERROR - Server error

API requests are rate-limited based on your subscription plan:

  • Free Plan: 100 requests per hour
  • Pro Plan: 1,000 requests per hour
  • Business Plan: 10,000 requests per hour

Rate limit headers are included in all responses:

X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 999
X-RateLimit-Reset: 1641034800

List webhook endpoints for an organization.

GET /organizations/{organization_id}/webhooks

Create a webhook endpoint to receive 9n9s events.

POST /organizations/{organization_id}/webhooks

Request Body:

{
"name": "My Webhook",
"url": "https://api.mycompany.com/webhooks/9n9s",
"events": ["monitor.down", "monitor.up", "incident.created"],
"secret": "webhook_secret_key"
}

For interactive API exploration, use our API playground or download our OpenAPI specification.