feat(emails): charge 1 credit per send (POST /api/emails)
Why
POST /api/emails charged nothing — sends (incl. agent/scheduled) were free and unmetered (chat#1815 billing item).
Pricing → 1 credit
1 credit = $0.01. Resend's per-email cost is ≤ $0.0004 (cheapest paid tier: Pro $20 / 50,000 emails; every tier is well under $0.01). Per the rule "round up to $0.01 if below, else charge at cost without markup" → 1 credit per email.
How
Mirrors the deep-research handler's gate→work→deduct pattern:
ensureCreditsOrShortCircuitgates the send — returns 402 (no send) if the account can't cover it, auto-recharging via a card on file when possible. It does not deduct.- Send.
- On success,
recordCreditDeduction({ creditsToDeduct: 1, source: "api" })— the atomic wallet+meter wrapper (one transaction:credits_usagedebit +usage_eventsinsert). A failed send (502) is not charged.
EMAIL_CREDIT_COST is a named, documented const. Only /api/emails charges — the shared processAndSendEmail (MCP send_email) path is unchanged.
Tests
6 handler tests green: gate→charge on success (cost 1, source: api), 402 + no send when insufficient, no charge on send failure. tsc/lint clean.
Tracked on chat#1815.
🤖 Generated with Claude Code
Summary by cubic
Charge 1 credit per email for POST /api/emails, with a credit gate upfront and deduction only after a successful send. Also tags usage with model_id = "POST /api/emails" and returns a CORS-safe 500 on unexpected credit gate failures.
-
New Features
- Gate with
ensureCreditsOrShortCircuit; 402 and no send if insufficient credits, with auto-recharge viaCREDIT_AUTO_RECHARGE_FALLBACK_SUCCESS_URL. - On success, deduct
EMAIL_CREDIT_COST = 1viarecordCreditDeduction({ source: "api", modelId: "POST /api/emails" }); no charge on 502 failures. - Only
POST /api/emailsis billed; the sharedprocessAndSendEmailpath remains unchanged.
- Gate with
-
Bug Fixes
- Wrap
sendEmailHandlerin try/catch to return a{ status: "error" }500 with CORS when the credit gate throws.
- Wrap
Summary by CodeRabbit
-
New Features
- Email sending now uses credit-based billing, checking available credits before sending.
- Email sends now include billing metadata to support usage tracking.
-
Bug Fixes
- Improved error handling so unexpected email send failures return a controlled response instead of an unhandled error.
- Prevents email attempts when credits are insufficient, helping avoid failed sends and inconsistent billing.