Skip to content

Developer Tools Overview

9n9s is built with developers in mind, providing a comprehensive suite of tools to integrate monitoring seamlessly into your development workflow. Whether you prefer programmatic APIs, native SDKs, command-line tools, or Infrastructure as Code, 9n9s has you covered.

The 9n9s REST API provides complete programmatic access to all platform features:

Key Features:

  • Full CRUD Operations: Manage monitors, projects, organizations, and alert rules
  • Real-time Data Access: Query monitor status, logs, and historical data
  • Webhook Management: Configure and manage notification channels
  • Team & Permission Management: Automate user access and role assignments
  • Analytics & Reporting: Extract monitoring data for custom dashboards and reports

API Characteristics:

  • RESTful Design: Predictable URL patterns and HTTP methods
  • JSON Throughout: Consistent JSON request/response format
  • Comprehensive Documentation: Interactive OpenAPI specifications
  • Rate Limiting: Intelligent rate limiting with clear headers
  • Versioning: Stable API versions with backward compatibility

Quick Example:

Terminal window
# Create a heartbeat monitor
curl -X POST https://api.9n9s.com/v1/heartbeats \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Daily Backup Job",
"schedule": "0 2 * * *",
"grace_period": 3600,
"project_id": "proj_abc123"
}'

Official SDKs provide idiomatic integration for popular programming languages:

from nines import Nines
# Initialize and use
nines = Nines("your-heartbeat-id")
# Context manager for automatic timing
with nines:
# Your job logic here
process_data()
# Or manual control
nines.start()
try:
result = process_data()
nines.pulse({"records_processed": result.count})
except Exception as e:
nines.fail(str(e))
import { Nines } from "@9n9s/sdk";
const nines = new Nines("your-heartbeat-id");
// Promise-based API
await nines.time(async () => {
const result = await processData();
return { records_processed: result.count };
});
// Event-driven approach
nines.onError((error) => {
console.error("Monitoring error:", error);
});
package main
import (
"github.com/9n9s-io/9n9s-go"
)
func main() {
client := nines.New("your-heartbeat-id")
// Defer for automatic cleanup
defer client.Pulse()
// Track execution with context
err := client.TimeContext(ctx, func() error {
return processData()
})
if err != nil {
client.Fail(err.Error())
}
}

The 9n9s CLI provides command-line access for automation and DevOps workflows:

Core Commands:

Terminal window
# Authentication
9n9s-cli login
9n9s-cli auth whoami
# Monitor Management
9n9s-cli heartbeat create --name "My Job" --schedule "0 2 * * *"
9n9s-cli uptime create --url "https://api.example.com/health"
9n9s-cli monitors list --project production
# Pulse Operations
9n9s-cli heartbeat pulse mon_abc123 --message "Job completed successfully"
9n9s-cli heartbeat pulse mon_abc123 --fail --message "Database connection failed"
# Configuration Management
9n9s-cli config apply --file monitoring.yml
9n9s-cli config export --project production

Script Integration:

#!/bin/bash
# backup.sh with monitoring
MONITOR_ID="mon_backup123"
# Signal start
9n9s-cli heartbeat pulse $MONITOR_ID --start
# Run backup
if pg_dump production_db > backup_$(date +%Y%m%d).sql; then
# Success with metrics
SIZE=$(du -h backup_*.sql | cut -f1)
9n9s-cli heartbeat pulse $MONITOR_ID --message "Backup completed: $SIZE"
else
# Failure
9n9s-cli heartbeat pulse $MONITOR_ID --fail --message "Backup failed with exit code $?"
fi

Webhooks enable real-time integration with external systems:

Outgoing Webhooks (Notifications):

{
"event": "monitor.status_changed",
"monitor": {
"id": "mon_abc123",
"name": "API Health Check",
"status": "DOWN",
"previous_status": "UP"
},
"incident": {
"started_at": "2024-01-15T10:30:00Z",
"duration_seconds": 300
},
"metadata": {
"response_time_ms": 5000,
"status_code": 500
}
}

Incoming Webhooks (Pulse Reception):

Terminal window
# Send custom pulses via webhook
curl -X POST https://webhook.9n9s.com/mon_abc123 \
-H "Content-Type: application/json" \
-d '{
"status": "success",
"metrics": {
"duration_ms": 1500,
"records_processed": 1000
},
"logs": "Processing completed successfully"
}'
terraform/monitoring.tf
terraform {
required_providers {
nines = {
source = "9n9s-io/nines"
version = "~> 1.0"
}
}
}
# Project configuration
resource "nines_project" "production" {
name = "Production Services"
organization_id = var.organization_id
settings = {
default_timezone = "UTC"
retention_days = 90
}
}
# Heartbeat monitors
resource "nines_heartbeat_monitor" "backup_job" {
name = "Database Backup"
project_id = nines_project.production.id
schedule = "0 2 * * *"
grace_period = 7200 # 2 hours
expected_runtime = {
min_seconds = 900 # 15 minutes
max_seconds = 3600 # 1 hour
}
tags = {
environment = "production"
service = "database"
criticality = "high"
team = "platform"
}
}
# Uptime monitors
resource "nines_uptime_monitor" "api_health" {
name = "API Health Endpoint"
project_id = nines_project.production.id
url = "https://api.example.com/health"
frequency = 60 # 1 minute
assertions = [
{
type = "STATUS_CODE"
operator = "EQUALS"
value = "200"
},
{
type = "RESPONSE_TIME"
operator = "LESS_THAN"
value = "2000"
},
{
type = "JSON_CONTENT"
path = "$.status"
operator = "EQUALS"
value = "healthy"
}
]
regions = ["us-east-1", "eu-west-1"]
}
# Alert rules
resource "nines_alert_rule" "critical_alerts" {
project_id = nines_project.production.id
name = "Critical Service Alerts"
conditions = {
monitor_tags = {
criticality = "high"
}
status_changes = ["UP_TO_DOWN", "UP_TO_DEGRADED"]
}
actions = [
{
type = "NOTIFICATION"
channel_id = data.nines_notification_channel.pagerduty.id
immediate = true
},
{
type = "NOTIFICATION"
channel_id = data.nines_notification_channel.slack_ops.id
delay_seconds = 0
}
]
}

TypeScript:

import * as nines from "@9n9s/pulumi";
import * as aws from "@pulumi/aws";
// Create monitoring project
const monitoringProject = new nines.Project("api-monitoring", {
name: "API Services Monitoring",
organizationId: "org_12345",
});
// Monitor Lambda functions
const lambdaFunctions = ["user-service", "payment-service", "notification-service"];
lambdaFunctions.forEach((functionName) => {
new nines.HeartbeatMonitor(`${functionName}-monitor`, {
name: `${functionName} Execution Monitor`,
projectId: monitoringProject.id,
schedule: "every 5 minutes",
gracePeriod: "2m",
tags: {
service: functionName,
environment: "production",
type: "lambda",
},
});
});
// Monitor API Gateway endpoints
const apiMonitor = new nines.UptimeMonitor("api-gateway", {
name: "API Gateway Health",
projectId: monitoringProject.id,
url: "https://api.example.com/health",
frequency: "30s",
assertions: [
{
type: "STATUS_CODE",
operator: "EQUALS",
value: "200",
},
{
type: "RESPONSE_TIME",
operator: "LESS_THAN",
value: "1000",
},
],
});
.9n9s/config.yml
api_version: v1
kind: MonitoringConfiguration
metadata:
organization: "example-corp"
environment: "production"
projects:
- name: "Core Services"
description: "Critical production services monitoring"
heartbeats:
- name: "Database Backup"
schedule: "0 2 * * *"
grace_period: "2h"
expected_runtime:
min: "15m"
max: "1h"
tags:
service: database
criticality: high
- name: "ETL Pipeline"
schedule: "0 1 * * *"
grace_period: "30m"
payload_keywords:
success: ["completed successfully", "pipeline finished"]
failure: ["error", "failed", "exception"]
tags:
service: data-processing
criticality: high
uptime:
- name: "Main API"
url: "https://api.example.com/health"
frequency: "1m"
regions: ["us-east-1", "eu-west-1"]
assertions:
- type: status_code
value: 200
- type: response_time
value: "<2000ms"
- type: json_content
path: "$.status"
value: "healthy"
- name: "Payment Gateway"
url: "https://payments.example.com/status"
frequency: "30s"
headers:
Authorization: "Bearer {{env.PAYMENT_API_TOKEN}}"
assertions:
- type: status_code
value: 200
- type: ssl_expiry
value: ">14d"
alert_rules:
- name: "Critical Service Failures"
conditions:
tags:
criticality: high
status_changes: [DOWN, DEGRADED]
actions:
- channel: pagerduty-ops
immediate: true
- channel: slack-alerts
delay: 0s
- name: "Non-Critical Alerts"
conditions:
tags:
criticality: [medium, low]
status_changes: [DOWN]
actions:
- channel: slack-alerts
delay: 5m
.github/workflows/deploy.yml
name: Deploy with Monitoring
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup 9n9s CLI
run: |
curl -L -o 9n9s-cli https://github.com/9n9s-io/cli/releases/latest/download/9n9s-cli-linux-amd64
chmod +x 9n9s-cli
sudo mv 9n9s-cli /usr/local/bin/
- name: Signal deployment start
run: |
9n9s-cli heartbeat pulse ${{ secrets.DEPLOYMENT_MONITOR_ID }} \
--start \
--message "Deployment started for commit ${{ github.sha }}"
env:
NINES_API_KEY: ${{ secrets.NINES_API_KEY }}
- name: Run tests
run: npm test
- name: Build application
run: npm run build
- name: Deploy to production
run: |
# Your deployment commands here
kubectl apply -f k8s/
kubectl rollout status deployment/app
- name: Update monitoring configuration
run: |
# Update monitor tags with deployment info
9n9s-cli heartbeat update ${{ secrets.APP_MONITOR_ID }} \
--tags "version=${{ github.sha }},deployed_by=${{ github.actor }},deployment_time=$(date -Iseconds)"
- name: Signal deployment success
if: success()
run: |
9n9s-cli heartbeat pulse ${{ secrets.DEPLOYMENT_MONITOR_ID }} \
--message "Deployment successful for ${{ github.sha }}"
- name: Signal deployment failure
if: failure()
run: |
9n9s-cli heartbeat pulse ${{ secrets.DEPLOYMENT_MONITOR_ID }} \
--fail \
--message "Deployment failed for ${{ github.sha }} at step ${{ github.job }}"
.gitlab-ci.yml
stages:
- test
- build
- deploy
- monitor
variables:
DEPLOYMENT_MONITOR: "mon_deploy123"
before_script:
- curl -L -o 9n9s-cli https://github.com/9n9s-io/cli/releases/latest/download/9n9s-cli-linux-amd64
- chmod +x 9n9s-cli && mv 9n9s-cli /usr/local/bin/
deploy:
stage: deploy
script:
- 9n9s-cli heartbeat pulse $DEPLOYMENT_MONITOR --start --message "GitLab deployment started"
- # Your deployment commands
- kubectl apply -f k8s/
- kubectl rollout status deployment/app
- 9n9s-cli heartbeat pulse $DEPLOYMENT_MONITOR --message "Deployment completed successfully"
after_script:
- |
if [ $CI_JOB_STATUS == "failed" ]; then
9n9s-cli heartbeat pulse $DEPLOYMENT_MONITOR --fail --message "Deployment failed in GitLab CI"
fi
docker-compose.monitoring.yml
version: "3.8"
services:
app:
build: .
environment:
- NINES_HEARTBEAT_ID=${APP_MONITOR_ID}
- NINES_API_KEY=${NINES_API_KEY}
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
interval: 30s
timeout: 10s
retries: 3
monitoring-sidecar:
image: 9n9s/cli:latest
environment:
- NINES_API_KEY=${NINES_API_KEY}
command: |
sh -c '
while true; do
if curl -f http://app:3000/health > /dev/null 2>&1; then
9n9s-cli heartbeat pulse ${APP_MONITOR_ID} --message "Health check passed"
else
9n9s-cli heartbeat pulse ${APP_MONITOR_ID} --fail --message "Health check failed"
fi
sleep 300
done
'
depends_on:
- app
monitoring-cronjob.yaml
apiVersion: batch/v1
kind: CronJob
metadata:
name: application-health-monitor
spec:
schedule: "*/5 * * * *"
jobTemplate:
spec:
template:
spec:
containers:
- name: health-checker
image: 9n9s/cli:latest
env:
- name: NINES_API_KEY
valueFrom:
secretKeyRef:
name: monitoring-secrets
key: api-key
- name: MONITOR_ID
value: "mon_k8s_health"
command:
- /bin/sh
- -c
- |
# Check if all replicas are ready
READY_REPLICAS=$(kubectl get deployment myapp -o jsonpath='{.status.readyReplicas}')
DESIRED_REPLICAS=$(kubectl get deployment myapp -o jsonpath='{.spec.replicas}')
if [ "$READY_REPLICAS" = "$DESIRED_REPLICAS" ] && [ "$READY_REPLICAS" -gt "0" ]; then
9n9s-cli heartbeat pulse $MONITOR_ID --message "All $READY_REPLICAS replicas ready"
else
9n9s-cli heartbeat pulse $MONITOR_ID --fail --message "Only $READY_REPLICAS of $DESIRED_REPLICAS replicas ready"
fi
restartPolicy: OnFailure
Terminal window
# Setup development environment
export NINES_API_KEY="dev_key_12345"
export NINES_BASE_URL="https://staging-api.9n9s.com" # Use staging environment
# Create test monitors
9n9s-cli heartbeat create \
--name "Local Development Test" \
--schedule "every 1 minute" \
--grace 300 \
--project-id "proj_dev"
# Test SDK integration
python -c "
from nines import Nines
nines = Nines('test-monitor-id', base_url='https://staging-api.9n9s.com')
nines.pulse('Development test successful')
print('SDK integration working!')
"
Terminal window
# Use ngrok for local webhook testing
ngrok http 8080
# Configure webhook endpoint
9n9s-cli notification-channel create \
--type webhook \
--url "https://abc123.ngrok.io/webhook" \
--name "Local Development Webhook"
# Test webhook delivery
curl -X POST https://abc123.ngrok.io/webhook \
-H "Content-Type: application/json" \
-d '{"test": "webhook payload"}'
  1. Rate Limiting: Respect API rate limits and implement exponential backoff
  2. Error Handling: Always handle API errors gracefully with retries
  3. Caching: Cache configuration data to reduce API calls
  4. Authentication: Securely store and rotate API keys regularly
  5. Monitoring: Monitor your own API usage and set up alerts for anomalies
  1. Error Handling: Always wrap SDK calls in try-catch blocks
  2. Timeouts: Configure appropriate timeouts for your use case
  3. Batching: Use batch operations when sending multiple pulses
  4. Context: Include relevant context and metadata in pulses
  5. Performance: Minimize impact on your application’s critical path
  1. Scripting: Use the CLI in scripts with proper error handling
  2. Configuration: Use environment variables for configuration
  3. Output Formats: Use JSON output for programmatic parsing
  4. Idempotency: Design scripts to be safely re-runnable
  5. Logging: Log CLI operations for debugging and auditing
  • GitHub Issues: Report bugs and request features
  • Discord Community: Real-time chat with other developers
  • Email Support: [email protected]
  • Enterprise Support: Dedicated support for enterprise customers

The 9n9s developer tools ecosystem is designed to integrate seamlessly into your existing workflows, whether you’re building simple scripts or complex enterprise applications. Choose the tools that best fit your development style and scale them as your monitoring needs grow.