Skip to main content

Credit Balances

If a plan sells a credit pool (“5,000 tasks for 99amonth,then99 a month, then 0.03 each”), these endpoints are how you watch it and act on it: two reads for the countdown, and two writes for the moments a human steps in. The numbers here come from the same balance path the dashboard reads. Your code, your dashboard, and your invoice can’t drift apart, because they’re all looking at one calculation.
Nothing stops at zero. The pool is a meter, never a breaker. A customer past their pool keeps working and the extra usage bills at the plan’s overage rate. If your product should stop serving at zero, your code makes that call: read the balance and decide. The Credit Pools recipe shows the pattern.

List credit balances

In plain English: one row per credit-pool subscription in your organization, emptiest first. Subscriptions whose plan doesn’t sell a pool aren’t listed at all. No pool means no row, never a fake zero. Method & URL:
Auth: any valid API key for your organization. Reads have no role restriction. Query parameters (all optional):
  • customerId (UUID) - Only pools belonging to this customer.
  • agentId (UUID) - Only pools on subscriptions for this agent.
  • belowPercent (number, -100 to 100) - Only pools with this percent of the pool (or less) still left. 20 is the near-empty cut the dashboard uses; 0 narrows it to pools at or past zero. Negative values are allowed because an overdrawn pool is past zero.
Example:
What you get back (200 OK):
Responses carry a short private cache (up to 30 seconds), and asOf tells you exactly when the numbers were computed.

Every field, in plain English

The two numbers that can disagree (and why both are right)

remainingUnits counts manual top-ups; overageInProgressUnits is the invoice’s own overage math, which never sees top-ups. A topped-up pool can honestly show remainingUnits: 1200 AND overageInProgressUnits: 300 at the same time: the customer has units left, and 300 units are billing as overage this period. The invoice always matches overageInProgressUnits, so the bill can never disagree with what this endpoint told you. Count down with remainingUnits; talk money with overageInProgressUnits.

Pools with no active period (noActivePeriod: true)

Two situations set this flag, and both are normal:
  • Never started. A subscription created without a start date (for example, one auto-created by the SDK’s first event) has no billing period, so its pool has nothing to count down in. Give the subscription a real start date and the countdown begins.
  • Between periods. A healthy pool whose period just ended sits in a short gap before the next period’s grant is minted. During that gap the row reads as a full, untouched pool (implicitFullPool: true), not a drained one. A gap between two mint points isn’t an empty pool.
Either way the row still appears, with periodStart and periodEnd as null.

Get one subscription’s balance

In plain English: the same row the list returns, for a single subscription. Method & URL:
Auth: any valid API key for your organization. Example:
What you get back (200 OK): one balance object, same fields as above. Errors:
  • 404 Not Found - The subscription isn’t in your organization, or its plan doesn’t sell a credit pool. A subscription without a pool has no pool number, never a zero one.
Using the SDK:
Using MCP: the get_credit_balances tool wraps both reads. Ask “who’s running out of credits?”

Add units to a pool (top-up)

In plain English: give a customer more units right now, mid-period. Goodwill credit, a side deal, a support resolution. The units never expire. Method & URL:
Auth: an API key or dashboard user with the owner, admin, or finance role. Anything less gets a 403: API-key callers see the allowed roles named in the message; dashboard sessions without the role get a generic forbidden. Body:
  • units (number, required) - How many usage units to add. Must be above zero. These are the same units the plan sells and the invoice bills, never dollars.
  • idempotencyKey (string, required, max 255) - Your own key for this top-up. Can’t be blank. Send the same key again and you get the SAME grant back instead of a second one, so a retry can never double-credit a customer. A UUID works.
  • note (string, optional, max 1000) - Why you added the units. Stored on the grant itself, so “why does this customer have extra credits?” is answered from the ledger row.
Example:
What you get back (201 Created):
created: false means this key was already used and you’re looking at the original grant (a replay, not a second credit). remainingUnits is the pool’s drawable balance after the top-up. createdBy records who added the units: the user’s ID for dashboard actions, or api-key:<key id> for API calls. The grant row itself is the audit trail. Rules worth knowing:
  • Top-ups never expire. The customer paid for them. Draw order burns the current period’s grant first, so a top-up remainder survives into the next period.
  • A top-up raises remainingUnits; it does NOT reduce overageInProgressUnits. The invoice’s overage math never sees top-ups. Overage already recorded this period stays on the bill.
  • Reuse a key only to retry the exact same top-up. A key reused with different units, or on a different subscription, is refused with a 409 so a copy-paste slip can’t misapply a credit.
Errors:
  • 400 Bad Request - units missing or not above zero, idempotencyKey blank, or the subscription’s plan sells no credit pool (the message tells you to add a credit-pool pricing strategy first).
  • 403 Forbidden - The caller isn’t owner, admin, or finance. API-key denials name the allowed roles; dashboard-session denials are a generic forbidden.
  • 404 Not Found - Subscription not found in your organization.
  • 409 Conflict - The idempotency key was already used with different units, or on a different subscription. The message spells out both the prior use and this request so you can see the mismatch.

Pause or resume alert emails

In plain English: quiet the credit-pool emails for one subscription (or turn them back on). You’ve talked to the customer, the overage is expected, and you don’t need four more emails about it. Method & URL:
Auth: owner, admin, or finance, same as the top-up. Body:
  • paused (boolean, required) - Always send the state you want, never a toggle: true silences this subscription’s pool emails, false turns them back on. Two identical calls leave the subscription in the same place.
Example:
What you get back (200 OK):
What pausing does (and doesn’t do):
  • Emails for this subscription stop. That’s the whole effect.
  • The countdown keeps counting, the balance stays visible everywhere, and the pool still appears on the dashboard’s Needs Attention page when it’s low (labeled Paused).
  • Un-pause mid-period and any alert stages the pool crossed while quiet can fire on the next evaluation. Stages re-arm every new billing period either way.
Errors:
  • 403 Forbidden - The caller isn’t owner, admin, or finance.
  • 404 Not Found - Subscription not found in your organization.

The alert emails these writes manage

As a pool drains, MarginFront emails at four stages: 50% used, 80% used, 95% used, and empty (remaining units at or below zero). One email per stage per billing period, only the highest newly-crossed stage sends, and every stage re-arms when the period rolls over. Recipients: the organization’s billing email if one is set, otherwise every owner and finance member. The Credit Pools recipe covers the ladder in full.
  • Credit Pools recipe: the full sell-a-pool walkthrough, including the self-limiting pattern for strict-prepaid products
  • Pricing Strategies: creating the pool with the three-number creditPool block
  • Errors: the general error-shape reference