API quota usage as engagement and upsell timing

For each customer on a usage-based plan, show daily call volume as % of cap. Flag accounts approaching 80% — the perfect upgrade moment.

Updated · published

markdown for agents →

difficulty intermediate · time to value 3 minutes · execution on demand

Start from this

For each customer on an API-call quota, show their daily usage as % of cap. Flag accounts approaching 80% — upsell trigger.

Why this matters

API-quota pricing turns engineering into a sales-influencing function. Every call your customer makes is both a feature use AND a step toward needing more. The hot signal — “this customer is about to hit the cap” — is the warmest upsell moment in your business. They’re already paying, they’ve already integrated, they’re feeling the limit.

Stripe Metering can compute usage but doesn’t surface “approaching limit” alerts in a usable form. Most teams find out a customer hit their cap when the customer gets a 429 and emails support angry.

Agentry computes per-account quota utilization in one HogQL query and ranks accounts by “about to hit the wall.” Sales gets the call list; engineering gets the signal too (capacity planning).

What you get

  • A per-account utilization table: account | quota | used_today | used_mtd | pct_of_cap | days_to_cap_at_current_rate
  • The accounts crossing thresholds (50/80/95/100%) sorted by how soon they’ll hit
  • A draft email per top-3 to the account’s primary contact: “you’re at 82% — here’s how upgrading helps”

Walk through it

You

For each customer on an API-call quota, show their daily usage as % of cap. Flag accounts approaching 80% — upsell trigger.

Agent

Computing per-account API call counts and joining against current quota.

Endpoint: POST /v1/projects/:project_id/analytics/query
Exact shape: /v1/openapi.json?path=%2Fv1%2Fprojects%2F%7Bproject_id%7D%2Fanalytics%2Fquery&method=post
Custom HogQL goes in the OpenAPI-defined `query` field.
Concept fields:
  query: "WITH quotas AS (SELECT properties.account_id AS aid, argMax(properties.api_quota_monthly, timestamp) AS quota FROM events WHERE event = 'quota_set' GROUP BY aid HAVING quota > 0), usage_mtd AS (SELECT properties.account_id AS aid, count() AS calls_mtd FROM events WHERE event = 'api_call' AND timestamp >= toStartOfMonth(now()) GROUP BY aid), usage_today AS (SELECT properties.account_id AS aid, count() AS calls_today FROM events WHERE event = 'api_call' AND timestamp >= toStartOfDay(now()) GROUP BY aid), days_passed AS (SELECT dateDiff('day', toStartOfMonth(now()), now()) + 1 AS days_in_mtd, dateDiff('day', toStartOfMonth(now()), toStartOfMonth(now() + INTERVAL 1 MONTH)) AS days_in_month) SELECT q.aid AS account, q.quota AS quota, COALESCE(u.calls_mtd, 0) AS used_mtd, COALESCE(t.calls_today, 0) AS used_today, round(COALESCE(u.calls_mtd, 0) * 100.0 / q.quota, 1) AS pct_of_cap, round(COALESCE(u.calls_mtd, 0) * 1.0 / d.days_in_mtd * d.days_in_month, 0) AS projected_eom, round(q.quota * 1.0 / nullIf(COALESCE(u.calls_mtd, 0) * 1.0 / d.days_in_mtd, 0)) AS days_to_cap_at_current_rate FROM quotas q LEFT JOIN usage_mtd u ON q.aid = u.aid LEFT JOIN usage_today t ON q.aid = t.aid CROSS JOIN days_passed d HAVING pct_of_cap >= 50 ORDER BY pct_of_cap DESC"
{
  "rows": [
    { "account": "acct_megacorp", "quota": 1000000, "used_mtd": 982400, "used_today": 41200, "pct_of_cap": 98.2, "projected_eom": 1340000, "days_to_cap_at_current_rate": 0 },
    { "account": "acct_innovate", "quota": 500000,  "used_mtd": 412000, "used_today": 18400, "pct_of_cap": 82.4, "projected_eom": 562000,  "days_to_cap_at_current_rate": 4 },
    { "account": "acct_acme",     "quota": 100000,  "used_mtd": 71000,  "used_today": 3100,  "pct_of_cap": 71.0, "projected_eom": 96900,   "days_to_cap_at_current_rate": 9 },
    { "account": "acct_globex",   "quota": 250000,  "used_mtd": 142000, "used_today": 4800,  "pct_of_cap": 56.8, "projected_eom": 194000,  "days_to_cap_at_current_rate": 22 }
  ]
}
Agent

Three accounts in the upgrade zone:

  1. megacorp — 98.2%, ALREADY OVER projected. They’ll hit the cap today or tomorrow. Their 429s are about to start; sales should call now, not after the angry email.
  2. innovate — 82.4%, ~4 days to cap. Perfect warm-lead moment. Reach out before they feel the pain.
  3. acme — 71%, ~9 days to cap. Worth a CSM “heads up, you’re trending toward your cap, want to discuss next tier?” message.

Globex at 57% is fine; mention in next QBR. Let me draft the megacorp + innovate emails:


To: [email protected] Subject: Heads up — you’re at 98% of your monthly API quota

Hi —

Your team’s pace this month puts you above your 1M-call cap by end of the month, likely as soon as tomorrow. Two options:

  1. Bump to the next tier (5M calls/mo) — same per-call price, headroom for growth.
  2. Stay on this tier and accept rate-limiting once you hit the cap.

Happy to set up a quick call to discuss which fits.

The output

API Quota Utilization (current month)

ACCOUNT         QUOTA      USED MTD    %     PROJ EOM    DAYS-TO-CAP
megacorp       1.0M        982,400    98%    1.34M           0  ★ CRITICAL
innovate       500k        412,000    82%      562k           4  ★ UPSELL NOW
acme           100k         71,000    71%      96.9k           9     warm
globex         250k        142,000    57%      194k          22     ok

ACTIONS:
  ★ megacorp:    AE call TODAY — they will exceed cap tomorrow
                  Draft email above
  ★ innovate:    AE outreach this week — warm lead window
  ★ acme:        CSM heads-up message
    globex:      track for next month

REVENUE OPPORTUNITY:
  If all 3 upgrade to next tier, +$3,500-$6,000 MRR.
  Cost of waiting: customer hits 429, fires angry email, downgrades or churns.

Setting it up

Two events needed:

1. Every API call as an analytics event (sampling OK if volume is huge):

// In your API middleware
app.use(async (req, res, next) => {
  await fetch(`https://api.agentry.sh/v1/analytics/`, {
    method: "POST",
    headers: {
      "Authorization": `Bearer ${process.env.AGENTRY_SERVER_API_KEY}`,
      "Content-Type": "application/json",
      "User-Agent": "myapp-api/1.0",  // REQUIRED — Cloudflare 403s default UAs
    },
    body: JSON.stringify({
      event: "api_call",
      distinct_id: req.account.id,
      properties: {
        account_id: req.account.id,
        endpoint: req.path,
        // skip waiting on this — fire-and-forget
      },
    }),
  }).catch(() => {});  // never break the request
  next();
});

At >1M calls/day, sample at 1-in-N and divide quota by N in the query — same shape, less ingest cost.

2. Quota changes (set or updated):

// On plan change OR explicit quota bump
await fetch(`https://api.agentry.sh/v1/analytics/`, {
  method: "POST",
  headers: { /* same */ "User-Agent": "myapp/1.0" },
  body: JSON.stringify({
    event: "quota_set",
    distinct_id: account.id,
    properties: {
      account_id: account.id,
      api_quota_monthly: account.plan.quota,
      plan: account.plan.name,
    },
  }),
});

Variations

  • “Same query for endpoint-level usage — which endpoints are the heaviest? Maybe there’s a more efficient API to suggest.”
  • “Find accounts that hit 100% last month — did they upgrade, downgrade, or just absorb the 429s?”
  • “For each over-cap account, compute the dollar value of their overage at the next tier’s rate. Use it in the sales pitch.”
  • “On demand, list accounts that crossed 80% in the last 24h and draft a #sales-pipeline summary for human review.”

Adapt this workflow in your own agent.

Ask your agent to map the starter prompt to your saved signal map, live events, and the current HTTP API before answering.

Agentry gives coding agents production context from errors, product analytics, and deploys through one HTTP API. Fetch and read https://agentry.sh/install.md completely, then install Agentry's full first-time telemetry baseline in this repository. I authorize device-code login, saving the owner key only to ~/.agentry/credentials.json, creating one Agentry project for this repository, and read-only inspection of shipped source plus hidden CI/provider configuration. Deeply analyze the product's business logic and complete value flow before choosing telemetry. Save the complete source-backed plan and show me its exact contents and hash. Until I explicitly approve that plan or request a replacement, do not edit app/CI source, place runtime/CI credentials, commit, exercise product traffic, start proof, push, or deploy. After approval, I authorize only the reviewed targets: place the required scoped browser/server/CI credentials through the established environment or secret mechanism, preserve existing telemetry, implement and test the baseline, commit it, push that reviewed commit when the shipped CI/provider path requires it, exercise safe proof paths with test/non-customer data, and perform one deployment through the reviewed shipped CI/provider path. Ask first if proof would charge money, contact a third party, change real customer data, or require new external access. After the plan is saved, immediately before every onboarding state-changing POST, GET current onboarding state, perform only its single returned next_action, then read state again; do not batch or infer later stages. Continue until status is verified, installation_complete is true, and next_action is null. Keep all secrets, source snapshots, proof markers, and scratch files outside the repository.

+ Full access
5.5 Extra High
  1. 1. Open your repo in Codex, Claude Code, Cursor etc.
  2. 2. Paste the install prompt.
  3. 3. Your agent reads the install doc and shows you an implementation plan for approval.