Skip to content

HTTP API Reference

All CritterWatch HTTP endpoints are implemented using Wolverine.HTTP and mounted under /api/critterwatch/*. They are automatically mapped by UseCritterWatch().

Bus-only queries don't appear here

The on-demand lookups for endpoint configuration, handler properties, handler source code, and HTTP-chain OpenAPI are bus queries, not HTTP endpoints — they go from the CritterWatch console to the monitored service over the message bus and the response comes back the same way. They live on the Inbound Commands page (RequestEndpointProperties, RequestMessageHandlerProperties, RequestHandlerSourceCode, RequestHttpChainOpenApi). If you're looking for an HTTP equivalent, there isn't one — invoke the matching command record over your transport.

Services

GET /api/critterwatch/services

Returns all monitored services as ServiceSummary documents.

Response: ServiceSummary[]

json
[
  {
    "id": "trip-service",
    "label": "Trip Service",
    "wolverineVersion": "5.28.0",
    "communicationUri": "amqp://trip-service",
    "tenancy": "None",
    "nodes": { ... },
    "agents": { ... },
    "messages": [ ... ],
    "messagingEndpoints": [ ... ]
  }
]

GET /api/critterwatch/services/{serviceName}

Returns a single service by name.

Response: ServiceSummary

Dead Letter Queue

POST /api/critterwatch/dead-letters/query

Query dead-lettered envelopes across services.

Request body:

json
{
  "serviceName": "trip-service",
  "tenantId": null,
  "messageType": "TripService.Messages.BookTrip",
  "exceptionType": null,
  "from": "2024-01-01T00:00:00Z",
  "to": null,
  "limit": 100
}

Response: DeadLetterEnvelope[]

POST /api/critterwatch/dead-letters/replay

Replay matching dead-lettered messages.

Request body:

json
{
  "serviceName": "trip-service",
  "tenantId": null,
  "messageType": "TripService.Messages.BookTrip",
  "limit": null
}

Response: { "replayedCount": 12 }

POST /api/critterwatch/dead-letters/discard

Permanently discard matching dead-lettered messages.

Request body: Same as replay.

Response: { "discardedCount": 12 }

POST /api/critterwatch/dead-letters/{envelopeId}/replay

Replay a single message by envelope ID.

Request body:

json
{
  "serviceName": "trip-service",
  "tenantId": null
}

POST /api/critterwatch/dead-letters/{envelopeId}/edit-replay

Edit a message body and replay.

Request body:

json
{
  "serviceName": "trip-service",
  "tenantId": null,
  "updatedBody": "{ \"tripId\": \"abc\", \"fare\": 450.00 }"
}

DELETE /api/critterwatch/dead-letters/{envelopeId}

Discard a single message.

Scheduled Messages

GET /api/critterwatch/scheduled-messages

Query scheduled messages.

Query parameters: serviceName, tenantId, messageType, from, to, status (upcoming/overdue/all)

PUT /api/critterwatch/scheduled-messages/{envelopeId}

Edit a scheduled message.

Request body:

json
{
  "serviceName": "trip-service",
  "tenantId": null,
  "updatedBody": "{ ... }",
  "newExecutionTime": "2024-06-01T12:00:00Z"
}

DELETE /api/critterwatch/scheduled-messages/{envelopeId}

Cancel a scheduled message.

Commands

POST /api/critterwatch/commands/pause-listener

Pause a listener on a service.

Request body: { "serviceName": "trip-service", "endpointName": "rabbitmq://trip-bookings" }

POST /api/critterwatch/commands/restart-listener

POST /api/critterwatch/commands/pause-all-listeners

POST /api/critterwatch/commands/restart-all-listeners

POST /api/critterwatch/commands/pause-projection

POST /api/critterwatch/commands/restart-projection

POST /api/critterwatch/commands/rebuild-projection

POST /api/critterwatch/commands/rewind-subscription

POST /api/critterwatch/commands/eject-node

POST /api/critterwatch/commands/trigger-election

POST /api/critterwatch/commands/add-tenant

POST /api/critterwatch/commands/remove-tenant

All command endpoints accept JSON bodies matching their corresponding command record types. See Inbound Commands for the full schema of each command.

Alerts

GET /api/critterwatch/alerts

Query alerts with optional filters: serviceName, status, severity, type.

POST /api/critterwatch/alerts/{alertId}/acknowledge

POST /api/critterwatch/alerts/{alertId}/snooze

POST /api/critterwatch/alerts/{alertId}/clear

Timeline

GET /api/critterwatch/timeline

Query timeline entries.

Query parameters: serviceName, category, severity, from, to, limit

System Health

GET /api/critterwatch/system-health

The console's own component health (GH-685) — not the health of monitored services. Console subsystems that detect they are broken (e.g. the metrics sample storage when its table schema cannot be reconciled) mark themselves degraded here with an actionable reason, instead of failing silently behind anonymous 500s.

Response:

json
{
  "status": "degraded",
  "components": [
    {
      "component": "metrics-store",
      "status": "Degraded",
      "reason": "CritterWatch cannot reconcile critterwatch.mt_doc_metricssample: ...",
      "changedAtUtc": "2026-07-12T12:00:00Z"
    }
  ]
}

status is "healthy" when no component is degraded. The same state also feeds the critterwatch-system ASP.NET Core health check, so hosts that call MapHealthChecks(...) report Degraded through their standard health endpoint. See the upgrade notes for the schema migration that motivated this surface.

Authentication

The HTTP API does not ship with built-in authentication. Add ASP.NET Core authorization middleware and use RequireAuthorization() on routes to protect the API.

Response Format

All responses use application/json. JSON serialization uses camelCase property names (via JsonNamingPolicy.CamelCase). Enums are serialized as string names.

Free for read-only monitoring. A commercial license is required for administrative actions and the MCP server.