Skip to content

feat(billing): rewrite historical usage endpoints to use Autumn API#3273

Open
firecrawl-spring[bot] wants to merge 1 commit intofeat/autumn-balance-endpointsfrom
feat/autumn-historical-endpoints
Open

feat(billing): rewrite historical usage endpoints to use Autumn API#3273
firecrawl-spring[bot] wants to merge 1 commit intofeat/autumn-balance-endpointsfrom
feat/autumn-historical-endpoints

Conversation

@firecrawl-spring
Copy link
Copy Markdown
Contributor

@firecrawl-spring firecrawl-spring Bot commented Apr 2, 2026

Summary

  • Replaces Supabase RPC calls with Autumn SDK for the credit-usage-historical and token-usage-historical endpoints (v1 + v2)
  • Fetches billing period boundaries from the active subscription and makes parallel events.aggregate calls per period
  • Resolves API key IDs back to human-readable names via the api_keys table to preserve backwards compatibility with the apiKey response field
  • Adds resolveApiKeyNames() and getHistoricalUsage() to services/autumn/usage.ts

Stacked on #3272 — merge that first.

Test plan

  • Verify GET /v1/team/credit-usage/historical returns billing-period-aligned usage bins
  • Verify GET /v2/team/credit-usage/historical returns same in camelCase
  • Verify GET /v1/team/token-usage/historical returns token values (credits × 15)
  • Verify GET /v2/team/token-usage/historical returns token values (credits × 15)
  • Verify ?byApiKey=true returns human-readable API key names (not numeric IDs)
  • Verify periods are sorted ascending by start date
  • Verify graceful fallback when no active subscription exists (returns empty array)

Summary by cubic

Rewrite historical credit and token usage endpoints (v1 and v2) to use the Autumn API, aligning results to billing periods and preserving response shape. Adds API key name resolution and parallel aggregation for faster, consistent usage data.

  • Refactors
    • Replaced Supabase RPC with Autumn events.aggregate across billing-period ranges.
    • byApiKey=true now groups by API key and resolves IDs to human-readable names for the apiKey field.
    • Introduced getHistoricalUsage() and resolveApiKeyNames() in services/autumn/usage.ts; shared by all four endpoints.
    • Returns [] when no active subscription; periods sorted ascending; token endpoints compute tokensUsed as creditsUsed * 15.

Written for commit ecb38dc. Summary will update on new commits.

Replace Supabase RPC calls with Autumn SDK for the credit-usage-historical
and token-usage-historical endpoints (v1 + v2). The new implementation
fetches billing period boundaries from the active subscription and makes
parallel events.aggregate calls for each period.

Also resolves API key IDs back to human-readable names via the api_keys
table to preserve backwards compatibility with the apiKey response field.

Co-Authored-By: micahstairs <micah@sideguide.dev>
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 issues found across 5 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="apps/api/src/services/autumn/usage.ts">

<violation number="1" location="apps/api/src/services/autumn/usage.ts:229">
P2: Period boundaries assume a constant period length, which is incorrect for monthly billing. Months range from 28–31 days, so subtracting a fixed `periodLengthSec` causes past period boundaries to drift from actual billing cycles (e.g., current period = March 1 → April 1 yields the previous period as Jan 29 → March 1 instead of Feb 1 → March 1). Consider fetching actual historical period boundaries from the subscription or using calendar-aware date arithmetic.</violation>

<violation number="2" location="apps/api/src/services/autumn/usage.ts:286">
P1: Missing `.sum` accessor on grouped aggregate values — likely yields `NaN` for all `byApiKey=true` responses.

The ungrouped path correctly uses `result.total?.[CREDITS_FEATURE_ID]?.sum`, but here the code accesses `values[CREDITS_FEATURE_ID]` without `.sum`. If the grouped value structure mirrors the total structure (as is standard for aggregate APIs), this returns an object instead of a number.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review, or fix all with cubic.

const current = apiKeyTotals.get(apiKeyId) ?? 0;
apiKeyTotals.set(
apiKeyId,
current + (values[CREDITS_FEATURE_ID] ?? 0),
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai Bot Apr 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: Missing .sum accessor on grouped aggregate values — likely yields NaN for all byApiKey=true responses.

The ungrouped path correctly uses result.total?.[CREDITS_FEATURE_ID]?.sum, but here the code accesses values[CREDITS_FEATURE_ID] without .sum. If the grouped value structure mirrors the total structure (as is standard for aggregate APIs), this returns an object instead of a number.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/api/src/services/autumn/usage.ts, line 286:

<comment>Missing `.sum` accessor on grouped aggregate values — likely yields `NaN` for all `byApiKey=true` responses.

The ungrouped path correctly uses `result.total?.[CREDITS_FEATURE_ID]?.sum`, but here the code accesses `values[CREDITS_FEATURE_ID]` without `.sum`. If the grouped value structure mirrors the total structure (as is standard for aggregate APIs), this returns an object instead of a number.</comment>

<file context>
@@ -123,3 +159,185 @@ export async function getTeamBalance(
+              const current = apiKeyTotals.get(apiKeyId) ?? 0;
+              apiKeyTotals.set(
+                apiKeyId,
+                current + (values[CREDITS_FEATURE_ID] ?? 0),
+              );
+            }
</file context>
Suggested change
current + (values[CREDITS_FEATURE_ID] ?? 0),
current + ((values as any)[CREDITS_FEATURE_ID]?.sum ?? 0),
Fix with Cubic

// Build period boundaries going backwards from the current period
const periods: Array<{ start: number; end: number }> = [];
for (let i = HISTORICAL_PERIOD_COUNT - 1; i >= 0; i--) {
const start = currentStart - i * periodLengthSec;
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai Bot Apr 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Period boundaries assume a constant period length, which is incorrect for monthly billing. Months range from 28–31 days, so subtracting a fixed periodLengthSec causes past period boundaries to drift from actual billing cycles (e.g., current period = March 1 → April 1 yields the previous period as Jan 29 → March 1 instead of Feb 1 → March 1). Consider fetching actual historical period boundaries from the subscription or using calendar-aware date arithmetic.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/api/src/services/autumn/usage.ts, line 229:

<comment>Period boundaries assume a constant period length, which is incorrect for monthly billing. Months range from 28–31 days, so subtracting a fixed `periodLengthSec` causes past period boundaries to drift from actual billing cycles (e.g., current period = March 1 → April 1 yields the previous period as Jan 29 → March 1 instead of Feb 1 → March 1). Consider fetching actual historical period boundaries from the subscription or using calendar-aware date arithmetic.</comment>

<file context>
@@ -123,3 +159,185 @@ export async function getTeamBalance(
+    // Build period boundaries going backwards from the current period
+    const periods: Array<{ start: number; end: number }> = [];
+    for (let i = HISTORICAL_PERIOD_COUNT - 1; i >= 0; i--) {
+      const start = currentStart - i * periodLengthSec;
+      const end = currentEnd - i * periodLengthSec;
+      periods.push({ start, end });
</file context>
Fix with Cubic

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants