Credits sind die Verbrauchs-Währung der Plattform (1 Credit = 0,02 €). Es gibt genau ein Abrechnungs-Muster: Reserve→Compute→Commit/Refund. Direkt abbuchen gibt es nicht, in keinem Codepfad.
In Modulen: der Harness bucht, nicht du
Modul-Code ruft die Credits-Engine nie selbst auf. Der Runs-Harness reserviert vor deinem runTool die creditsPerUse aus dem Manifest, committet bei Erfolg und erstattet bei jedem Fehler:
export const runTool: ModuleCompute = async (ctx, { payload }) => {
// Credits sind hier bereits reserviert.
const result = await doTheWork(ctx, payload);
return { output: result }; // Rückgabe → Commit
// Werfen → Refund + Fehl-Notification. Mehr musst du nicht tun.
};User-Trust-Regel: jeder technische Fehler erstattet. Das erledigt der Harness; baue kein eigenes Refund-Handling.
In Plattform-Code: die CreditsEngine
Server-Code außerhalb des Harness (z.B. eigene Batch-Aktionen) nutzt die Engine direkt. Sie ist eine Factory, Apps halten einen gecachten Handle:
import { createCreditsService, InsufficientCreditsError } from "@reosa/sdk";
const credits = createCreditsService(db, { includedCreditsForPlan });
const r = await credits.reserve(ctx, {
moduleId: "homestaging",
creditCost: 8, // 0.1 bis 100000, eine Nachkommastelle
description: "Batch-Lauf", // optional, max 300 Zeichen
});
// r: { id, periodId, credits, expiresAt } · Reservierung verfällt nach 5 Minuten
try {
const { actualCredits } = await compute();
await credits.commit(ctx, r.id, actualCredits); // actualCredits optional
} catch (error) {
await credits.refund(ctx, r.id, "generation failed");
throw error;
}Die wichtigsten Eigenschaften:
reserve(ctx, { moduleId, creditCost, description? })hält den Betrag im Tenant-Pool. Parallele Aufrufe serialisieren auf der Perioden-Zeile; überbuchen ist unmöglich.commit(ctx, reservationId, actualCredits?)bucht ohneactualCreditsexakt den reservierten Betrag. MitactualCreditswird nach unten abgerechnet: berechnet wirdmin(reserviert, actualCredits), der Rest wird freigegeben. Mehr als reserviert wird nie berechnet (Worst-Case-Schutz für den Tenant). Gedacht für Batch-Aktionen, die vorab schätzen und die echte Summe erst am Ende kennen.refund(ctx, reservationId, reason)gibt die volle Reservierung frei;reasonlandet im Ledger.- Reservierungen verfallen nach 5 Minuten (
RESERVATION_TTL_MS). Abgelaufene Reservierungen räumt der nächstereserve()-Aufruf lazy ab; ein verspäteter Commit auf eine verfallene Reservierung schlägt fehl. - Credits tragen eine Nachkommastelle. Beträge werden an jeder Grenze mit
roundCredits()auf 1 Dezimale gerundet (1.55 → 1.6). - Lese-APIs:
getBalance(ctx),history(ctx, { limit, before }),usageSummary(ctx)(Verbrauch nach Modul und Mitglied).
Fehlerbilder
Alle Fehler erben von SdkError; branche mit instanceof oder code:
| Fehler | code | Bedeutung |
|---|---|---|
InsufficientCreditsError | INSUFFICIENT_CREDITS | Der Workspace-Pool deckt den Betrag nicht (und Extended Usage greift nicht). |
MemberAllocationExceededError | MEMBER_ALLOCATION_EXCEEDED | Das persönliche Monats-Kontingent des Mitglieds ist erschöpft, obwohl der Pool noch Guthaben hätte. Zeige "dein Kontingent ist aufgebraucht", nicht "Workspace leer". |
OverageCapReachedError | OVERAGE_CAP_REACHED | Extended Usage ist aktiv, aber das selbst gesetzte Monats-Budget ist erreicht. Harter Block. |
SdkError | RESERVATION_NOT_PENDING | Commit/Refund auf eine Reservierung, die fehlt, schon abgerechnet oder verfallen ist. |
Der Harness übersetzt diese Fehler für die Tool-UI in den ModuleRunOutcome-Code insufficient_credits; verlinke dort auf die Credit-Verwaltung statt eine rohe Fehlermeldung zu zeigen.
Anzeige-Regel: kleine Beträge verstecken
Beträge unter SMALL_CREDIT_COST_THRESHOLD (= 10 Credits, aus @reosa/config) werden in der UI standardmäßig nicht angezeigt. Abgebucht wird immer korrekt; nur die Anzeige entfällt.
- Anzeige-Elemente kleiner Beträge tragen die CSS-Klasse
small-credit-cost. Die globale Stylesheet-Regel blendet sie aus, solange die Nutzer:in die persönliche Einstellung "Kleine Credit-Beträge anzeigen" nicht aktiviert hat. Baue keine eigene Sichtbarkeits-Logik. - Buttons nennen die Aktion, nie den Preis: "KI-Briefing erstellen", nicht "KI-Briefing (2 Credits)".
- Kosten-Bestätigungs-Dialoge nur für wirklich teure Aktionen ab der Schwelle.
Credit-Tools vs. Add-on-Tools
pricing: "credits"(Default): jeder Lauf buchtcreditsPerUseüber den Harness.pricing: "addon": das Tool wird als Monats-Add-on lizenziert (Preis + enthaltene Voll-Läufe inTOOL_ADDONSin@reosa/config, optional mit Tiers). Das Kontingent-Limit greift beim Start eines Kern-Laufs; ein laufender Lauf wird nie mitten im Flow wegen Credits oder Kontingent gestoppt. Kleinere Einzel-Aktionen des Tools kosten weiterhin normal Credits über den Harness, still und ohne Preis-Anzeige. Der Marketplace zeigt für Add-on-Tools den Add-on-Preis, keine Credit-Labels.
Weiterführend
Kosten-Schätzung für KI-Läufe: REOS AI (estimateCredits). Der komplette Modul-Vertrag: Modul-Guide.