API & Technical Reference

Technical documentation for SmartOps webhooks, response formats, authentication, and integration patterns for developers.

API & Technical Reference

Technical documentation for developers and system integrators working with SmartOps.

🔄 Response Formats

Success Response

{
  "status": "success",
  "data": {
    "message": "Formatted response",
    "attachments": [],
    "actions": []
  }
}

Error Response

{
  "status": "error",
  "error": {
    "code": "PERMISSION_DENIED",
    "message": "Insufficient permissions to stop instance",
    "details": "Required IAM action: ec2:StopInstances"
  }
}

Interactive Response

{
  "status": "pending",
  "data": {
    "message": "Confirmation required",
    "actions": [
      {
        "type": "confirm",
        "label": "Yes, proceed",
        "action": "confirm_action_123"
      },
      {
        "type": "cancel",
        "label": "Cancel",
        "action": "cancel_action_123"
      }
    ]
  }
}

📊 Webhooks API

Teams Webhook Endpoint

POST https://api.ohlala.cloud/prod/api/messages

Headers:

Authorization: Bearer {bot-framework-token}
Content-Type: application/json

Body:

{
  "type": "message",
  "text": "list instances",
  "from": {
    "id": "user-id",
    "name": "User Name"
  },
  "conversation": {
    "id": "conversation-id"
  }
}

Health Check Endpoint

GET https://api.ohlala.cloud/prod/health

Response:

{
  "status": "healthy",
  "version": "1.0.0",
  "timestamp": "2024-03-20T10:30:00Z"
}

🔐 Authentication & Security

Bot Framework Authentication

SmartOps uses Microsoft Bot Framework authentication:

  1. JWT Token Validation: All incoming requests verified
  2. Azure AD Integration: User identity through Teams
  3. API Gateway Authorizer: Lambda-based request validation

Request Flow

Teams → Bot Framework → API Gateway → Lambda Authorizer → ECS Task

Security Headers

Required headers for webhook requests:

Authorization: Bearer <jwt-token>
Content-Type: application/json
User-Agent: Microsoft-BotFramework/3.1

🔧 Error Codes

Common Error Responses

Code Description Resolution
AUTHENTICATION_FAILED Invalid Bot Framework token Check Azure Bot credentials
PERMISSION_DENIED Insufficient IAM permissions Review ECS task role
RATE_LIMITED Too many requests Implement exponential backoff
INSTANCE_NOT_FOUND EC2 instance doesn’t exist Verify instance ID
SSM_UNAVAILABLE SSM agent not responding Check instance SSM status
BEDROCK_ERROR AI service unavailable Check Bedrock model access
VALIDATION_ERROR Invalid request format Check request structure

Error Response Format

{
  "status": "error",
  "error": {
    "code": "RATE_LIMITED",
    "message": "Too many requests",
    "details": "Rate limit: 10 requests per minute",
    "retry_after": 60
  },
  "timestamp": "2024-03-20T10:30:00Z",
  "request_id": "abc-123-def"
}

📡 Rate Limiting

Default Limits

  • Per User: 10 requests per minute
  • Per Team: 100 requests per minute
  • Burst Capacity: 20 requests per 10 seconds

Rate Limit Headers

Response includes rate limit information:

X-RateLimit-Limit: 10
X-RateLimit-Remaining: 8
X-RateLimit-Reset: 1647782400
X-RateLimit-Retry-After: 45

Handling Rate Limits

Implement exponential backoff:

async function sendCommand(command, retryCount = 0) {
  try {
    const response = await fetch('/api/messages', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ text: command })
    });

    if (response.status === 429) {
      const retryAfter = response.headers.get('X-RateLimit-Retry-After');
      const delay = Math.min(1000 * Math.pow(2, retryCount), 60000);

      await new Promise(resolve => setTimeout(resolve, delay));
      return sendCommand(command, retryCount + 1);
    }

    return response.json();
  } catch (error) {
    console.error('Request failed:', error);
  }
}

🏗️ Custom Integration Patterns

Webhook Integration

For custom applications integrating with SmartOps:

const webhook = {
  url: 'https://your-api-gateway-url/prod/api/messages',
  headers: {
    'Authorization': 'Bearer <bot-framework-token>',
    'Content-Type': 'application/json'
  }
};

async function sendSmartOpsCommand(command, userId) {
  const payload = {
    type: 'message',
    text: command,
    from: {
      id: userId,
      name: 'API User'
    },
    conversation: {
      id: `api-${userId}-${Date.now()}`
    }
  };

  const response = await fetch(webhook.url, {
    method: 'POST',
    headers: webhook.headers,
    body: JSON.stringify(payload)
  });

  return response.json();
}

Programmatic Commands

Examples of programmatic usage:

// Get instance list
const instances = await sendSmartOpsCommand('list instances', 'user123');

// Check specific instance health
const health = await sendSmartOpsCommand('check health i-0abc123def', 'user123');

// Execute remote command
const result = await sendSmartOpsCommand('execute "df -h" on web-server-01', 'user123');

📋 Response Schemas

Instance List Response

{
  "status": "success",
  "data": {
    "instances": [
      {
        "instanceId": "i-0abc123def",
        "name": "web-server-01",
        "type": "t3.medium",
        "state": "running",
        "platform": "linux",
        "privateIp": "10.0.1.45",
        "publicIp": "54.123.45.67",
        "tags": {
          "Name": "web-server-01",
          "Environment": "production"
        },
        "metrics": {
          "cpuUtilization": 45.2,
          "memoryUtilization": 62.1,
          "diskUtilization": 38.7
        }
      }
    ],
    "summary": {
      "total": 5,
      "running": 4,
      "stopped": 1
    }
  }
}

Health Report Response

{
  "status": "success",
  "data": {
    "overall_health": "warning",
    "summary": {
      "healthy": 12,
      "warning": 3,
      "critical": 1
    },
    "issues": [
      {
        "instanceId": "i-0def456ghi",
        "severity": "critical",
        "issue": "High CPU usage",
        "details": "CPU at 95% for 30 minutes",
        "recommendation": "Consider scaling or investigating process"
      }
    ],
    "trends": {
      "cpu_trend": "+15%",
      "cost_trend": "+8%",
      "instance_count_change": "+2"
    }
  }
}

Command Execution Response

{
  "status": "success",
  "data": {
    "command": "systemctl status nginx",
    "instanceId": "i-0abc123def",
    "executionTime": 1.2,
    "output": "● nginx.service - The nginx HTTP Server\n   Loaded: loaded\n   Active: active (running)",
    "exitCode": 0,
    "commandId": "cmd-abc-123"
  }
}

🔌 Slack Integration (Future)

Webhook Differences

When Slack support is added, the webhook format will differ:

{
  "token": "verification-token",
  "team_id": "T1234567890",
  "api_app_id": "A1234567890",
  "event": {
    "type": "app_mention",
    "text": "<@U1234567890> list instances",
    "user": "U0987654321",
    "ts": "1234567890.123456",
    "channel": "C1234567890"
  }
}

🛠️ Development Tools

Testing Webhooks

Use curl to test webhook endpoints:

# Test health endpoint
curl -X GET https://your-api-gateway-url/prod/health

# Test message endpoint
curl -X POST https://your-api-gateway-url/prod/api/messages \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer <token>" \
  -d '{
    "type": "message",
    "text": "list instances",
    "from": {"id": "test-user", "name": "Test User"},
    "conversation": {"id": "test-conversation"}
  }'

SDK Examples

Python SDK Usage

import requests

class SmartOpsClient:
    def __init__(self, webhook_url, bot_token):
        self.webhook_url = webhook_url
        self.headers = {
            'Authorization': f'Bearer {bot_token}',
            'Content-Type': 'application/json'
        }

    def send_command(self, command, user_id):
        payload = {
            'type': 'message',
            'text': command,
            'from': {'id': user_id, 'name': 'API User'},
            'conversation': {'id': f'api-{user_id}'}
        }

        response = requests.post(
            f'{self.webhook_url}/api/messages',
            headers=self.headers,
            json=payload
        )

        return response.json()

# Usage
client = SmartOpsClient('https://your-api-gateway-url/prod', 'your-bot-token')
result = client.send_command('list instances', 'user123')

📖 Next Steps

Need Help?