Docs

Integration guide

1. Create a project and a key

From your dashboard, create a project for the API you want to track, then generate an API key — optionally scoped to a specific client app.

2. Option A — ASP.NET Core middleware (automatic)

Reference the UsageWatch.Client project, then register it in Program.cs:

builder.Services.AddUsageWatch(options =>
{
    options.ApiKey = builder.Configuration["UsageWatch:ApiKey"]!;
    options.IngestBaseUrl = "https://usagewatch.yourdomain.com";
});

var app = builder.Build();
app.UseRouting();
app.UseUsageWatch();  // after UseRouting, before endpoints
app.MapControllers();

Every request is queued in memory and delivered by a background service — it never blocks or slows down your API's response.

Telling UsageWatch which client made the call

UsageWatch never guesses who's calling — you tell it, using whichever of these fits your app (checked in this order, first match wins):

builder.Services.AddUsageWatch(options =>
{
    options.ApiKey = "uw_live_...";
    options.IngestBaseUrl = "https://usagewatch.yourdomain.com";

    // 1. Full control — read it however your app already knows the caller
    options.ClientIdentifierResolver = ctx => ctx.Items["TenantId"]?.ToString();

    // 2. Or just read a header your callers send (this is the default: "X-Client-Id")
    options.ClientIdHeaderName = "X-Client-Id";

    // 3. Or a query string param
    options.ClientIdQueryParamName = "client_id";

    // 4. Or a claim on the authenticated user (JWT / API-key auth)
    options.ClientIdClaimType = "client_id";
});

If none of the configured strategies resolve a value for a given request, the call is still tracked and counted toward quota — it just won't show up broken out by client until one does.

3. Option B — plain REST call (any language)

POST https://usagewatch.yourdomain.com/api/ingest/usage
X-Api-Key: uw_live_your_key_here
Content-Type: application/json

{
  "endpoint": "/v1/orders/123",
  "method": "GET",
  "statusCode": 200,
  "responseTimeMs": 42,
  "clientIdentifier": "acme-corp"
}

Returns 200 with the current month's usage and quota, or 429 if the project's plan enforces a hard limit and the call is over quota.

4. Manual tracking from code

Inject IUsageWatchClient anywhere — background jobs, gRPC, custom endpoints — for full control over what gets recorded:

public class OrdersService(IUsageWatchClient usageWatch)
{
    public void Handle()
    {
        usageWatch.Track("/v1/orders", "POST", 201, 84, clientIdentifier: "acme-corp");
    }
}

Quota enforcement

Each project has a monthly quota (from its plan, or a custom override). Turn on "Block calls once quota is exceeded" in project settings to have the ingestion endpoint return 429 Too Many Requests once a project goes over — otherwise calls are still logged and counted, just never blocked.