Skip to main content

Limits

Money Service limits are split into two categories: technical limits (enforced by the database schema, immutable) and business limits (defined by the tenant's Billing plan, cached in Valkey).


Technical Limits (Immutable)

LimitValueEnforcement
Amount typePositive BIGINT integer (cents)PostgreSQL schema
Minimum amount1 cent (amount > 0)Application layer + DB CHECK
Zero amountNot allowed → 400 Bad RequestApplication layer
Negative amountNot allowed → 400 Bad RequestApplication layer
Negative balanceImpossiblePostgreSQL CHECK (balance >= 0)
BIGINT max9,223,372,036,854,775,807 cents ≈ $92 quadrillionPostgreSQL data type

The BIGINT ceiling is a technical boundary, not a business limit. No tenant will realistically approach it in the lifetime of the platform. It provides multi-decade headroom without a schema migration.


Business Limits (Billing Plan)

Business limits are defined per tenant in the Billing Service and can be adjusted by the Platform Owner:

LimitDefault valueEnv variable
Max single transaction amount$100 000 (10 000 000 cents)Configurable per tenant plan
Max wallet balance$1 000 000 (100 000 000 cents)Configurable per tenant plan

These are defaults for a standard plan. The Billing Service can configure higher limits for enterprise tenants.


Limits Caching (Valkey)

The Money Service does not query the Billing Service on every transaction. Limits are fetched once and cached in Valkey:

Valkey key: billing:plan_limits:{tenantId}
Value: { "maxTxAmount": 10000000, "maxBalance": 100000000 }
TTL: 5 minutes

Cache Resolution Flow

Transaction request arrives:

1. Check Valkey: billing:plan_limits:{tenantId}
┌─ HIT: use cached limits (may be up to 5 min stale)
│ → execute transaction

└─ MISS: gRPC call to Billing Service
┌─ Billing OK: cache result in Valkey (TTL 5 min)
│ → execute transaction

└─ Billing DOWN: FAIL-CLOSED
→ 503 Service Unavailable
Transaction is NOT executed

Fail-Closed Behavior

When Billing is unreachable and the cache is cold (miss):

HTTP/1.1 503 Service Unavailable
Content-Type: application/json

{
"type": "https://api.septemcore.com/problems/service-unavailable",
"status": 503,
"detail": "Cannot verify transaction limits: Billing Service is unavailable.",
"code": "LIMITS_UNAVAILABLE"
}

Why fail-closed: Financial safety takes precedence over availability. Executing a transaction without verifying limits could violate tenant plan constraints, compliance rules, or fraud controls. The 5-minute Valkey TTL ensures this path is hit only in genuine outage scenarios — not during normal spikes.

Billing statusCache statusResult
OnlineHit (fresh ≤ 5 min)✅ Use cache
OnlineMiss✅ Fetch from Billing, cache, proceed
DownHit (stale but present)✅ Use stale cache (safe)
DownMiss503 Service Unavailable (fail-closed)

Limit Violations

When a transaction exceeds a business limit, the operation is rejected before any database write:

POST https://api.septemcore.com/v1/wallets/01j9paw1t000000000000000/credit
Idempotency-Key: ...
Content-Type: application/json

{ "amount": 15000000 }

Response 422 Unprocessable Entity:

{
"type": "https://api.septemcore.com/problems/limit-exceeded",
"status": 422,
"detail": "Transaction amount 15000000 cents exceeds the plan limit of 10000000 cents ($100,000).",
"code": "LIMIT_EXCEEDED",
"limit": "maxTxAmount",
"value": 15000000,
"max": 10000000
}

Balance limit violation (credit would push balance above the plan maximum):

{
"type": "https://api.septemcore.com/problems/limit-exceeded",
"status": 422,
"code": "LIMIT_EXCEEDED",
"limit": "maxBalance",
"detail": "This credit would push the wallet balance to 105000000 cents, exceeding the plan limit of 100000000 cents ($1,000,000)."
}

Insufficient Funds

When a debit or hold amount exceeds available:

{
"type": "https://api.septemcore.com/problems/insufficient-funds",
"status": 400,
"detail": "Insufficient funds: available balance is 3000 cents, requested 5000 cents.",
"code": "INSUFFICIENT_FUNDS",
"available": 3000,
"requested": 5000
}

Error Reference

ScenarioHTTPCode
amount is zero400INVALID_AMOUNT
amount is negative400INVALID_AMOUNT
Transaction amount exceeds plan max422LIMIT_EXCEEDED (limit: maxTxAmount)
Credit would exceed max balance422LIMIT_EXCEEDED (limit: maxBalance)
Insufficient available400INSUFFICIENT_FUNDS
Billing down, cache cold503LIMITS_UNAVAILABLE