# Pathrule Pattern: Paddle Billing (1.0.0)
# ::pathrule:package:paddle-billing

### [RULE] Process Paddle webhooks idempotently and by occurrence time  (path: /src/webhooks/paddle)
<!-- scope: folder | priority: high | strict -->

Paddle webhook delivery is at least once and related events can arrive out of order, so receipt order cannot define billing truth. Authenticate the raw request before parsing, persist the event id and occurred_at value, and make the projection update conditional on the incoming evidence being newer than the state already applied.

- Acknowledge quickly after durable capture and move business processing to a retryable worker.
- Deduplicate by Paddle event_id and keep successful replays as no-ops with an auditable receipt.
- Compare occurred_at or a stronger entity version before changing subscription, transaction, or access state.
- Quarantine unrecognized event shapes and repeated failures instead of returning success while dropping them.

Verification: Deliver duplicates and reverse the order of paid, subscription-created, and completed events; confirm one durable receipt per event and the same final projection.

---

### [RULE] Grant access from verified billing evidence  (path: /src/access)
<!-- scope: folder | priority: high | strict -->

A browser success page is user-controlled navigation, not durable payment evidence. Create access only from authenticated Paddle events or an explicit server-side Paddle lookup, then store the provider ids and evidence that caused each transition. Keep access projection separate from the raw billing objects so temporary delivery gaps do not erase history.

- Map each price or product to an internal entitlement set through versioned configuration.
- Record the Paddle customer, transaction, subscription, event, and occurrence time behind every access change.
- Define grace, past-due, canceled, paused, and resumed behavior as explicit transitions rather than scattered status checks.
- Make repeated grants and revocations idempotent and preserve the previous state for audit.

Verification: Skip the return page, replay the webhook, delay subscription creation, and restore a paused subscription; confirm access converges from verified evidence alone.

---

### [RULE] State proration intent on every subscription item change  (path: /src/billing/paddle)
<!-- scope: folder | priority: high | strict -->

Changing Paddle subscription items can alter what is charged now, deferred, credited, or left unchanged. Never let a generic update helper choose that commercial decision implicitly. The application command must name the proration billing mode, expected effective time, actor, reason, and preview accepted by the customer or operator.

- Validate that the requested price, quantity, currency, and billing interval are compatible before calling Paddle.
- Present or log the previewed immediate charge, credit, and next recurring total before confirmation.
- Use one idempotent internal change intent and reconcile ambiguous provider responses by subscription lookup.
- Persist the requested and resulting item sets so support can explain a later invoice.

Verification: Exercise upgrade, downgrade, quantity change, interval change, retry after timeout, and no-proration cases; confirm the result matches the named mode.

---

### [MEMORY] Transactions, payments, and subscriptions answer different questions  (path: /src/billing/paddle)

Do not compress Paddle transactions, payments, and subscriptions into a single local status. A transaction describes priced commercial items and its billing lifecycle, a payment describes an attempt to collect money for that transaction, and a subscription describes the recurring relationship that can produce later transactions. Financial records are preserved and post-billing changes are represented through adjustments rather than deletion.

Keep the three provider identifiers on separate local records and link them to the same internal account and order context. Decide which object is authoritative for each question: transaction for the amount and completion evidence, payment for attempt diagnostics, and subscription for renewal or item state. See /src/access for the derived product-access projection and /src/webhooks/paddle for ordering rules.

---

### [MEMORY] Customer management URLs are temporary capabilities  (path: /src/billing/paddle)

Paddle customer and subscription management URLs are temporary capabilities. Caching one in a user profile, database row, support note, or analytics event turns a short-lived delegated action into a stale or leaked link. Generate the appropriate URL on demand after authenticating the user and authorizing access to the internal account connected to the Paddle customer.

Return the link only through the requesting secure session, avoid logging the full value, and let expiration require a fresh request. Never accept a customer or subscription id from the client without resolving it through the server-owned account mapping. If a custom management action exists, keep the same authorization and audit boundary. See /src/access for ownership checks that precede link generation.

---

### [SKILL] reconcile-paddle-access  (path: /src/billing/paddle)

---
name: reconcile-paddle-access
description: Compare Paddle billing records with the local access projection and repair explainable drift.
---

# Reconcile Paddle Access

1. Select a bounded account or time window and export local Paddle ids, event receipts, subscription snapshots, transaction states, adjustments, and access transitions.
2. Fetch the current Paddle customer, subscription, and relevant transactions; preserve raw evidence and retrieval time without overwriting prior snapshots.
3. Classify differences as delayed delivery, out-of-order application, missing mapping, manual provider change, configuration drift, or unsupported state.
4. Replay the smallest verified event or run an explicit idempotent repair command; never edit access without linking the provider evidence and reason.
5. Re-run the comparison and record counts, unresolved cases, owner, and next review time.

A successful run proves that the same provider facts produce the same local access state and that every repair can be explained from retained evidence.
