Billing & BYOC rendering — pay per operation, bring your own content
Render modes
Set renderMode at campaign create (PLATFORM | BYOC). The mode locks as soon as any recipient passes SCREENED. BYOC is incompatible with canvas multi-step flows (v1). In BYOC the platform never spends its AI on your emails: the render cron skips the campaign, prepare only audits content you already submitted, and recipients/rerender just resets rows to SCREENED awaiting your resubmission.
BYOC intake
Submission itself is free. Limits: ≤100 items per call, subject ≤998 chars, bodyHtml ≤256 KB, bodyText ≤64 KB. Content must be FINISHED text — unresolved {{placeholders}} are rejected per-item at intake. Rows must be in stage SCREENED.
curl -s -X POST "https://api.live-direct-marketing.online/api/campaigns/$CAMPAIGN/recipients/content" \
-H "Authorization: Bearer $LDM_KEY" -H "Content-Type: application/json" \
-d '{
"items": [
{ "recipientId": "cmx...", "subject": "Hi Anna", "bodyHtml": "<p>Finished personalised email</p>" }
]
}'
# → { "accepted": 1, "rejected": [], "awaitingAudit": 1 }Mandatory paid audit (no bypass, any mode)
- Every email — platform-rendered or BYOC — passes the audit gate before it can be sent. The audit is the ONLY writer of the READY stage; the send point additionally verifies a content hash fixed at audit time.
- Audit iterations are billed per email: passed =
audit, failed =audit_failed(50% of the audit price). - Rejections return COARSE categories only (
auditCategories: spam_signals, quality_low, broken_personalization, link_policy, language_mix, formatting, policy_violation, other). No detailed rationale by design — the auditor is not an oracle to probe. - Limits: ≤5 paid audit iterations per recipient (then CREATIVE_FAILED); a campaign that burns more than 5× its recipient count in audit iterations is set to AUDIT_BLOCKED — manual moderation only.
Pricing & balance
One account balance (USD). Default prices per email-operation: platform_render $0.002, audit $0.001, audit_failed $0.0005, send $0.0005 (per-tenant overrides possible). GET /api/billing/balance returns balance, the pricing table and topUpUrl; GET /api/billing/ledger returns the itemised charge journal, including background cron charges.
// Every paid response (MCP/A2A clients) carries:
"_billing": { "operation": "audit", "cost": 0.05, "currency": "USD", "balance_after": 12.35 }
// 402 on insufficient funds — nothing is partially executed:
{ "status": 402, "code": "insufficient_balance",
"required": 0.098, "balance": 0.01, "currency": "USD",
"topUpUrl": "https://app.live-direct-marketing.online/crm/settings?tab=ai" }Background conveyor (cron render/audit/send) pauses the campaign with circuitBreaker.reason = insufficient_balance when the balance runs out — top up in the dashboard, then POST /api/campaigns/:id/resume. There is NO top-up via API or MCP.