# Payments And Monetization

> Use when adding payments, subscriptions, quotas or metering to a service. Merchant-of-record versus payment gateway reasoning, mock-first integration, webhook discipline, the subscription lifecycle, quota and metering with deliberate fail-open, layered entitlement enforcement, the self-hosted tenant mode switch, and introducing paid tiers to an existing user base.

- Skill: `konradcinkusz/payments-and-monetization` (Agent Skill, multi-file: 2 files)
- Install (CLI): `npx skillmds@latest add konradcinkusz/payments-and-monetization`
- Raw SKILL.md: https://api.skillmd.com/api/skills/konradcinkusz/payments-and-monetization/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Integrations & APIs
- Author: konradcinkusz (https://skillmd.com/u/konradcinkusz)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/konradcinkusz/payments-and-monetization

---


# Payments, subscriptions and metering

**Read [`references/PAYMENTS-AND-MONETIZATION.md`](references/PAYMENTS-AND-MONETIZATION.md) before applying any of this.**
That file is the standard; everything below it is a summary to help you decide
whether this skill applies and to check your work afterwards.

## What this standard covers

- The model in one paragraph
- Merchant of record vs payment gateway
- Mock-first
- Webhooks
- Subscription lifecycle
- Quota and metering
- Entitlement enforcement is layered
- Tenant mode
- Introducing paid tiers to an existing user base

## Failure modes

| Symptom | Cause |
|---|---|
| Every production webhook rejected | Signature header name assumed, not confirmed; or webhook secret unset (correct behaviour — set the secret) |
| Webhooks accepted in production without signatures | The mock-mode fallback was made symmetric; restore reject-in-production |
| Subscription grants applied twice | No idempotency on provider event id; redelivery is normal, not exceptional |
| Cancellations never take effect | Lifecycle events landing in the mapper's default branch; only payment events were handled |
| Paying user loses days after early renewal | Extension computed from payment date instead of `max(expiry, payment date)` |
| Renewal-day usage missing from the new period | Quota period reset from the extended expiry base, not the payment date |
| Webhook dropped: "order not found" | Provider webhook beat your checkout write; synthesize from payload and backfill |
| Users blocked when the quota service restarts | Thin client fails closed; only 429 may block |
| Workspace counter wrong forever | State-counted quota incremented on events instead of re-synced from the database |
| Free users briefly see paid features | Client gate is optimistic while loading — by design; the API policy is the boundary |

## Checklist

Per payment integration:

- [ ] Mock mode: synthetic checkout + authenticated simulate endpoint running the real webhook path; simulate returns 403 outside mock mode
- [ ] Raw-body signature verification, constant-time compare; unsigned → accept in mock, reject in production
- [ ] Idempotency keyed on provider event id; amount and currency validated server-side
- [ ] Provider events mapped to an internal vocabulary; default branch logged; lifecycle events explicitly handled
- [ ] Webhook-before-order tolerated (cache → DB → synthesize; upsert backfills)
- [ ] Extension math never shortens; metering period resets from payment date
- [ ] Cancel-at-period-end + resume; downgrade locks excess resources with a reason, never deletes
- [ ] Provider vocabulary and DTOs confined to the boundary (P11)

Per metering setup:

- [ ] Central quota authority; thin fail-open client in the shared kernel (429 blocks, everything else allows, ~5 s timeout)
- [ ] Consume-before vs consume-after decided and written down
- [ ] `-1` = unlimited sentinel; tier profiles as pure functions; lazy period reset
- [ ] State-counted quotas re-synced at read; event-counted quotas append-only; race-safe row creation
- [ ] Usage event log kept alongside counters
- [ ] `TenantMode` implemented at token issuance only; frontend hides pricing via a flag
- [ ] Paid-tier rollout has an announce + grace period plan

---

Generated from [`docs/guides/PAYMENTS-AND-MONETIZATION.md`](https://github.com/konradcinkusz/architecture-standards/blob/main/docs/guides/PAYMENTS-AND-MONETIZATION.md) by `scripts/build-marketplace.mjs`. Do not edit this file: change the source document, or its entry in `catalog/marketplace.catalog.json`, and re-run the generator.

