Two agents, one limit, one refused.
All posts
4 min read
by

Knowing what your agent actually did

Delivery rates, failures and usage for work Anlyon does for your agent, plus a record of every production call it made: the operational half of an audit trail.

observabilitymonitoringagentstutorial

Editor's note, 3 October 2026. This post covers an earlier namespace. It still runs on the same API. Anlyon's product today is shared limits and receipts for AI agent actions.

"The agent handled it" is not an answer you can give an auditor, a customer, or yourself at 3am. You need to know what it actually did: what was delivered, what failed, what retried, and how that changed this week. Because your agent asks Anlyon for an action by name and Anlyon makes the production call itself, Anlyon can record what happened to each one: the action version that ran, what the destination replied, who approved it, and which run caused it. That record lives on the invocation (actions.invocations(), and Outcomes and receipts in the docs). This post covers the aggregate view on top of it: delivery statistics for messages and schedules, failure rates and usage over time. The other half of the audit trail is the run and span tree.

Analytics Overview

Anlyon tracks:

  • Message delivery statistics
  • Success and failure rates
  • Delivery latency
  • Schedule execution history
  • Usage patterns over time

Getting Started

import { Client } from '@anlyonhq/sdk';

const client = new Client({
  apiKey: process.env.ANLYON_API_KEY!,
});

// Get message analytics
const analytics = await client.analytics.messages({
  startDate: '2025-01-01T00:00:00Z',
  endDate: '2025-01-31T23:59:59Z',
});

console.log(`Total messages: ${analytics.data.total}`);
console.log(`Delivered: ${analytics.data.delivered}`);
console.log(`Failed: ${analytics.data.failed}`);
console.log(`Success rate: ${analytics.data.successRate}%`);

Message Analytics

Overall Statistics

const stats = await client.analytics.messages({
  startDate: '2025-01-01T00:00:00Z',
  endDate: '2025-01-31T23:59:59Z',
});

console.log('Message Statistics:', {
  total: stats.data.total,
  delivered: stats.data.delivered,
  failed: stats.data.failed,
  pending: stats.data.pending,
  successRate: `${stats.data.successRate}%`,
  averageLatency: `${stats.data.averageLatency}ms`,
});

Time-Series Data

Get hourly or daily breakdowns:

const timeSeries = await client.analytics.messages({
  startDate: '2025-01-01T00:00:00Z',
  endDate: '2025-01-31T23:59:59Z',
  granularity: 'daily', // or 'hourly'
});

timeSeries.data.timeSeries.forEach(entry => {
  console.log(`${entry.date}: ${entry.delivered} delivered, ${entry.failed} failed`);
});

Filter by Status

Analyze specific message states:

// Get only failed messages
const failed = await client.analytics.messages({
  startDate: '2025-01-01T00:00:00Z',
  endDate: '2025-01-31T23:59:59Z',
  status: 'failed',
});

// Get only delivered messages
const delivered = await client.analytics.messages({
  startDate: '2025-01-01T00:00:00Z',
  endDate: '2025-01-31T23:59:59Z',
  status: 'delivered',
});

Schedule Analytics

Track CRON schedule execution:

const scheduleStats = await client.analytics.schedules({
  startDate: '2025-01-01T00:00:00Z',
  endDate: '2025-01-31T23:59:59Z',
});

console.log('Schedule Statistics:', {
  totalExecutions: scheduleStats.data.totalExecutions,
  successful: scheduleStats.data.successful,
  failed: scheduleStats.data.failed,
  successRate: `${scheduleStats.data.successRate}%`,
});

Usage Analytics

Monitor your usage and quotas:

// Get current usage
const usage = await client.billing.getUsage();

console.log('Current Usage:', {
  messagesToday: usage.data.usage.messagesToday,
  messagesThisMonth: usage.data.usage.messagesThisMonth,
  bandwidth: usage.data.usage.bandwidth,
  remaining: usage.data.remaining,
});

// Get usage history
const history = await client.billing.getUsageHistory({ days: 30 });

history.data.history.forEach(day => {
  console.log(`${day.date}: ${day.messagesPublished} messages published`);
});

Building Dashboards

Real-Time Dashboard

async function buildDashboard() {
  // Get current stats
  const [messages, schedules, usage] = await Promise.all([
    client.analytics.messages({
      startDate: new Date(Date.now() - 24 * 60 * 60 * 1000).toISOString(),
      endDate: new Date().toISOString(),
    }),
    client.analytics.schedules({
      startDate: new Date(Date.now() - 24 * 60 * 60 * 1000).toISOString(),
      endDate: new Date().toISOString(),
    }),
    client.billing.getUsage(),
  ]);

  return {
    messages: {
      total: messages.data.total,
      successRate: messages.data.successRate,
      averageLatency: messages.data.averageLatency,
    },
    schedules: {
      totalExecutions: schedules.data.totalExecutions,
      successRate: schedules.data.successRate,
    },
    usage: {
      messagesToday: usage.data.usage.messagesToday,
      messagesThisMonth: usage.data.usage.messagesThisMonth,
      remaining: usage.data.remaining,
    },
  };
}
async function getTrends(days: number = 30) {
  const endDate = new Date();
  const startDate = new Date();
  startDate.setDate(startDate.getDate() - days);

  const analytics = await client.analytics.messages({
    startDate: startDate.toISOString(),
    endDate: endDate.toISOString(),
    granularity: 'daily',
  });

  return analytics.data.timeSeries.map(entry => ({
    date: entry.date,
    delivered: entry.delivered,
    failed: entry.failed,
    successRate: (entry.delivered / (entry.delivered + entry.failed)) * 100,
  }));
}

Setting Up Alerts

Usage Alerts

Anlyon automatically sends alerts when you approach quota limits. Configure thresholds:

await client.notifications.updatePreferences({
  quotaAlertThresholds: [50, 75, 90, 100], // Alert at these percentages
  emailRecipients: ['ops@example.com'],
  enabledTypes: ['quota_warning', 'quota_exceeded'],
});

Failure Rate Alerts

Monitor for delivery failure spikes:

async function checkFailureRate() {
  const stats = await client.analytics.messages({
    startDate: new Date(Date.now() - 60 * 60 * 1000).toISOString(), // Last hour
    endDate: new Date().toISOString(),
  });

  const failureRate = (stats.data.failed / stats.data.total) * 100;

  if (failureRate > 10) { // Alert if > 10% failure rate
    // Send alert to monitoring system
    console.warn(`High failure rate detected: ${failureRate}%`);
  }
}

Integration with Monitoring Tools

Prometheus Metrics

import { Registry, Counter, Gauge } from 'prom-client';

const registry = new Registry();
const messagesTotal = new Counter({
  name: 'relay_messages_total',
  help: 'Total messages published',
  registers: [registry],
});

const messagesDelivered = new Counter({
  name: 'relay_messages_delivered',
  help: 'Messages delivered successfully',
  registers: [registry],
});

async function updateMetrics() {
  const stats = await client.analytics.messages({
    startDate: new Date(Date.now() - 60 * 60 * 1000).toISOString(),
    endDate: new Date().toISOString(),
  });

  messagesTotal.inc(stats.data.total);
  messagesDelivered.inc(stats.data.delivered);
}

Datadog Integration

import { StatsD } from 'node-statsd';
const statsd = new StatsD();

async function sendToDatadog() {
  const stats = await client.analytics.messages({
    startDate: new Date(Date.now() - 60 * 60 * 1000).toISOString(),
    endDate: new Date().toISOString(),
  });

  statsd.gauge('relay.messages.total', stats.data.total);
  statsd.gauge('relay.messages.delivered', stats.data.delivered);
  statsd.gauge('relay.messages.failed', stats.data.failed);
  statsd.gauge('relay.success_rate', stats.data.successRate);
}

Best Practices

  1. Monitor regularly: Set up automated checks for key metrics
  2. Track trends: Look for patterns in success rates over time
  3. Set appropriate alerts: Don't alert on every failure, focus on trends
  4. Analyze failures: Use analytics to understand why messages fail
  5. Optimize based on data: Use latency metrics to optimize endpoints

Next Steps

Monitor with confidence using Anlyon analytics! 📊

Free tier, no credit card. One command if you use Claude or Cursor.

$ claude mcp add anlyon -- npx -y @anlyonhq/mcp-server