# B2B Subscription Execution Plan

## 1. Objective

Build a reliable B2B subscription management system that supports:

- Free trials
- Paid subscriptions
- Payment pending states
- Grace periods
- Payment retry logic
- Suspension
- Cancellation
- Reactivation
- Admin overrides
- Auditable subscription lifecycle events
- Entitlement-based access control

The system must avoid ambiguous subscription states and must separate billing status from product access.

---

## 2. Guiding Principles

### 2.1 Subscription Status Is Not Access

A subscription status describes the billing lifecycle.

Access should be determined by an entitlement layer.

Example:

```text
subscription.status = "past_due"
entitlement.access_level = "limited"
```

Do not scatter billing checks throughout the product.

---

### 2.2 Events Are the Source of Truth

Every important lifecycle action must create an immutable event.

Examples:

```text
subscription.created
trial.started
trial.ended
payment.succeeded
payment.failed
subscription.suspended
subscription.canceled
subscription.reactivated
```

The current subscription state may be stored directly for performance, but every change must be explainable through historical events.

---

### 2.3 Webhooks Are Unreliable Until Reconciled

Billing provider webhooks may be delayed, duplicated, or arrive out of order.

The system must support:

- Idempotent webhook processing
- Event deduplication
- Provider reconciliation jobs
- Manual admin review

---

## 3. Core Status Model

Use the following subscription statuses:

```text
trialing
active
payment_pending
past_due
suspended
canceled
expired
paused
```

Optional advanced statuses:

```text
refunded
chargeback
```

Avoid adding more statuses unless there is a real operational need. Status bloat is how billing systems become folklore.

---

## 4. Status Definitions

| Status | Meaning |
|---|---|
| `trialing` | Customer is in a free or paid trial period. |
| `active` | Customer has a valid paid subscription. |
| `payment_pending` | Payment is expected but has not completed. |
| `past_due` | Payment is overdue after the pending window. |
| `suspended` | Access is blocked due to unresolved billing issue. |
| `canceled` | Subscription has been canceled and will not renew. |
| `expired` | Trial or subscription ended without renewal. |
| `paused` | Subscription is intentionally paused. |

---

## 5. Recommended B2B Policy

### 5.1 Trial Policy

Default policy:

```text
Trial length: 14 days
Payment method required: Yes
Trial eligibility: One trial per company or billing account
Trial conversion: Automatic
```

Trial rules:

- A customer may start one trial per company workspace.
- A valid payment method should be required before trial activation.
- Trial start and end dates must be stored.
- Trial users should receive notifications before conversion.
- Trial abuse checks should be applied at account and company level.

Recommended fields:

```json
{
  "trial_start_at": "2026-05-25T00:00:00Z",
  "trial_end_at": "2026-06-08T00:00:00Z",
  "trial_used": true,
  "payment_method_required": true
}
```

---

### 5.2 Trial Ending Policy

At trial end:

| Condition | Result |
|---|---|
| Payment succeeds | Move to `active` |
| Payment fails | Move to `payment_pending` |
| No payment method exists | Move to `expired` or require payment method before trial starts |

Recommended rule:

```text
If payment method is required, no payment method means trial cannot start.
```

This is stricter, but cleaner.

---

### 5.3 Active Subscription Policy

An active subscription means:

- Payment is valid
- Current billing period is open
- Customer has access based on purchased plan
- Renewal should occur automatically

Fields:

```json
{
  "status": "active",
  "current_period_start": "2026-06-08T00:00:00Z",
  "current_period_end": "2026-07-08T00:00:00Z",
  "cancel_at_period_end": false
}
```

---

### 5.4 Payment Pending Policy

Payment pending begins when payment is required but incomplete.

Triggers:

- Trial conversion payment failed
- Renewal payment failed
- Upgrade payment requires confirmation
- Payment provider marks payment as incomplete
- Bank transfer or invoice payment is awaiting settlement

Default B2B policy:

```text
Payment pending timeout: 7 days
Access during payment pending: Full access
Notifications: Day 0, Day 3, Day 6
```

B2B payments often involve finance teams, approvals, cards expiring, invoice routing, and other thrilling artifacts of corporate civilization.

---

### 5.5 Past Due Policy

After the payment pending window expires:

```text
payment_pending → past_due
```

Default policy:

```text
Past due duration: 7 days
Access: Limited access
Admin visibility: Required
Customer notification: Required
```

Limited access may include:

- Read-only access
- No new projects
- No exports
- No premium actions
- Existing data remains accessible

---

### 5.6 Suspension Policy

After the past due window expires:

```text
past_due → suspended
```

Default policy:

```text
Suspension starts: 14 days after first failed payment
Access: Blocked or read-only
Data retention: Continue retaining account data
Admin notification: Required
```

Suspended accounts should not be deleted.

Suspension means:

- Billing issue is unresolved
- Customer can still update payment method
- Customer can still contact support
- Admins can manually extend access if needed

---

### 5.7 Cancellation Policy

After the suspension window expires:

```text
suspended → canceled
```

Default B2B cancellation policy:

```text
Cancel after: 30 days unpaid
Access: Removed
Renewal: Disabled
Data: Retained according to data retention policy
```

Cancellation should be final for that subscription instance, but the customer may create a new subscription or reactivate if allowed.

---

## 6. Full Lifecycle Flow

```text
none
  ↓
trialing
  ↓
active
  ↓
payment_pending
  ↓
past_due
  ↓
suspended
  ↓
canceled
```

Alternative trial expiration flow:

```text
none
  ↓
trialing
  ↓
expired
```

Reactivation flow:

```text
payment_pending / past_due / suspended / canceled
  ↓
payment succeeds
  ↓
active
```

---

## 7. Transition Table

| Current Status | Event | New Status | Notes |
|---|---|---|---|
| `none` | Trial started | `trialing` | Customer begins trial |
| `none` | Paid subscription started | `payment_pending` | First payment required |
| `payment_pending` | Payment succeeded | `active` | Grant paid access |
| `trialing` | Trial ended and payment succeeded | `active` | Convert trial |
| `trialing` | Trial ended and payment failed | `payment_pending` | Start recovery flow |
| `trialing` | Trial ended without payment method | `expired` | No access |
| `active` | Renewal payment succeeded | `active` | Extend period |
| `active` | Renewal payment failed | `payment_pending` | Start dunning |
| `payment_pending` | Payment succeeded | `active` | Restore normal billing |
| `payment_pending` | Timeout reached | `past_due` | Payment unresolved |
| `past_due` | Payment succeeded | `active` | Restore access |
| `past_due` | Timeout reached | `suspended` | Restrict access |
| `suspended` | Payment succeeded | `active` | Restore access |
| `suspended` | Timeout reached | `canceled` | End subscription |
| `active` | User cancels | `active` with `cancel_at_period_end = true` | Access until period end |
| `active` | Admin cancels immediately | `canceled` | Used for fraud, abuse, or special cases |
| `canceled` | Customer reactivates | `payment_pending` | Payment required |
| `expired` | Customer subscribes | `payment_pending` | Payment required |
| `paused` | Resume date reached | `active` | Resume subscription |

---

## 8. Timeout Policy

Recommended B2B timeline:

| Day | Status | Access | Action |
|---:|---|---|---|
| 0 | `payment_pending` | Full | Payment fails, notify billing owner |
| 3 | `payment_pending` | Full | Retry payment, send reminder |
| 6 | `payment_pending` | Full | Final warning before past due |
| 7 | `past_due` | Limited | Restrict risky actions |
| 14 | `suspended` | Read-only or blocked | Notify admins and billing owner |
| 30 | `canceled` | No access | Cancel subscription |

Recommended constants:

```json
{
  "payment_pending_timeout_days": 7,
  "past_due_timeout_days": 7,
  "suspension_timeout_days": 16,
  "cancel_after_days_unpaid": 30
}
```

---

## 9. Payment Retry Policy

Use a configurable retry schedule.

Recommended retry schedule:

```json
{
  "retry_schedule_days": [0, 3, 6, 10, 14],
  "max_retry_attempts": 5
}
```

Retry rules:

- Retry immediately after first failure.
- Retry again after 3 days.
- Retry again before moving to past due.
- Retry again before suspension.
- Retry one final time before cancellation.
- Stop retries if the customer cancels.
- Stop retries if invoice is manually voided.
- Stop retries if subscription is canceled.

---

## 10. Access Control Policy

Access must be derived through entitlements.

### Access Levels

```text
full
limited
read_only
none
```

### Mapping

| Subscription Status | Access Level |
|---|---|
| `trialing` | `full` |
| `active` | `full` |
| `payment_pending` | `full` |
| `past_due` | `limited` |
| `suspended` | `read_only` or `none` |
| `canceled` | `none` |
| `expired` | `none` |
| `paused` | `read_only` |

### Entitlement Decision Example

```json
{
  "workspace_id": "workspace_123",
  "subscription_id": "sub_123",
  "subscription_status": "past_due",
  "access_level": "limited",
  "reason": "payment_overdue",
  "valid_until": "2026-06-22T00:00:00Z"
}
```

---

## 11. Data Model

### 11.1 Subscriptions Table

```sql
CREATE TABLE subscriptions (
  id UUID PRIMARY KEY,
  workspace_id UUID NOT NULL,
  customer_id UUID NOT NULL,
  plan_id UUID NOT NULL,

  status TEXT NOT NULL,

  billing_interval TEXT NOT NULL,
  current_period_start TIMESTAMP,
  current_period_end TIMESTAMP,

  trial_start_at TIMESTAMP,
  trial_end_at TIMESTAMP,

  payment_pending_since TIMESTAMP,
  payment_due_at TIMESTAMP,

  past_due_since TIMESTAMP,
  suspended_at TIMESTAMP,

  cancel_at_period_end BOOLEAN DEFAULT FALSE,
  canceled_at TIMESTAMP,
  ended_at TIMESTAMP,

  retry_count INTEGER DEFAULT 0,
  max_retry_count INTEGER DEFAULT 5,

  created_at TIMESTAMP NOT NULL DEFAULT NOW(),
  updated_at TIMESTAMP NOT NULL DEFAULT NOW()
);
```

---

### 11.2 Subscription Events Table

```sql
CREATE TABLE subscription_events (
  id UUID PRIMARY KEY,
  subscription_id UUID NOT NULL,
  workspace_id UUID NOT NULL,

  event_type TEXT NOT NULL,
  source TEXT NOT NULL,
  payload JSONB NOT NULL,

  occurred_at TIMESTAMP NOT NULL,
  created_at TIMESTAMP NOT NULL DEFAULT NOW()
);
```

---

### 11.3 Invoices Table

```sql
CREATE TABLE invoices (
  id UUID PRIMARY KEY,
  subscription_id UUID NOT NULL,
  workspace_id UUID NOT NULL,

  provider_invoice_id TEXT,
  status TEXT NOT NULL,

  amount_due INTEGER NOT NULL,
  amount_paid INTEGER DEFAULT 0,
  currency TEXT NOT NULL,

  due_at TIMESTAMP,
  paid_at TIMESTAMP,
  failed_at TIMESTAMP,
  voided_at TIMESTAMP,

  created_at TIMESTAMP NOT NULL DEFAULT NOW(),
  updated_at TIMESTAMP NOT NULL DEFAULT NOW()
);
```

---

### 11.4 Payment Attempts Table

```sql
CREATE TABLE payment_attempts (
  id UUID PRIMARY KEY,
  invoice_id UUID NOT NULL,
  subscription_id UUID NOT NULL,

  provider_payment_id TEXT,
  status TEXT NOT NULL,

  failure_code TEXT,
  failure_message TEXT,

  attempted_at TIMESTAMP NOT NULL,
  created_at TIMESTAMP NOT NULL DEFAULT NOW()
);
```

---

### 11.5 Entitlements Table

```sql
CREATE TABLE entitlements (
  id UUID PRIMARY KEY,
  workspace_id UUID NOT NULL,
  subscription_id UUID NOT NULL,

  feature_key TEXT NOT NULL,
  access_level TEXT NOT NULL,

  starts_at TIMESTAMP NOT NULL,
  ends_at TIMESTAMP,

  created_at TIMESTAMP NOT NULL DEFAULT NOW(),
  updated_at TIMESTAMP NOT NULL DEFAULT NOW()
);
```

---

## 12. Event Catalog

### Subscription Events

```text
subscription.created
subscription.updated
subscription.activated
subscription.payment_pending
subscription.past_due
subscription.suspended
subscription.canceled
subscription.expired
subscription.reactivated
subscription.paused
subscription.resumed
```

### Trial Events

```text
trial.started
trial.ending_soon
trial.ended
trial.converted
trial.expired
```

### Payment Events

```text
payment.started
payment.succeeded
payment.failed
payment.requires_action
payment.retry_scheduled
payment.retry_failed
payment.retry_exhausted
```

### Invoice Events

```text
invoice.created
invoice.finalized
invoice.paid
invoice.payment_failed
invoice.voided
invoice.refunded
```

### Risk Events

```text
chargeback.created
chargeback.resolved
fraud.review_required
admin.override_created
```

---

## 13. Notification Plan

### 13.1 Trial Notifications

| Timing | Message |
|---|---|
| Trial start | Welcome and trial end date |
| 7 days before trial end | Reminder |
| 3 days before trial end | Conversion reminder |
| 1 day before trial end | Final reminder |
| Trial converted | Payment receipt and activation |
| Trial expired | Upgrade prompt |

---

### 13.2 Payment Failure Notifications

| Timing | Recipient | Message |
|---|---|---|
| Day 0 | Billing owner | Payment failed |
| Day 3 | Billing owner + admins | Payment retry failed |
| Day 6 | Billing owner + admins | Final warning before past due |
| Day 7 | Billing owner + admins | Account is past due |
| Day 14 | Billing owner + admins | Account suspended |
| Day 30 | Billing owner + admins | Subscription canceled |

Every notification should include:

- Company name
- Plan name
- Amount due
- Due date
- Payment update link
- Consequence of non-payment
- Support contact

---

## 14. Admin Console Requirements

Admins must be able to:

- View subscription status
- View payment history
- View invoice history
- View retry attempts
- View lifecycle events
- Extend trial
- Extend grace period
- Retry payment
- Cancel immediately
- Cancel at period end
- Suspend account
- Reactivate account
- Grant temporary access
- Change plan
- Add internal notes

All admin actions must create audit events.

Audit record:

```json
{
  "admin_id": "admin_123",
  "action": "extend_grace_period",
  "reason": "Enterprise customer requested invoice processing time",
  "previous_state": "past_due",
  "new_state": "payment_pending",
  "created_at": "2026-06-15T00:00:00Z"
}
```

---

## 15. Webhook Processing Requirements

Webhook processor must support:

- Signature verification
- Idempotency keys
- Event deduplication
- Out-of-order event handling
- Retry-safe processing
- Dead-letter queue
- Manual replay

Webhook events to handle:

```text
customer.subscription.created
customer.subscription.updated
customer.subscription.deleted
invoice.created
invoice.finalized
invoice.paid
invoice.payment_failed
payment_intent.succeeded
payment_intent.payment_failed
charge.dispute.created
charge.refunded
```

Processing rule:

```text
Never trust webhook order.
Always compare provider timestamp, local state, and event history.
```

---

## 16. Scheduled Jobs

Create scheduled jobs for:

| Job | Frequency | Purpose |
|---|---:|---|
| Trial ending reminder job | Daily | Notify customers before trial ends |
| Trial expiration job | Hourly | Expire or convert ended trials |
| Payment retry job | Hourly | Retry failed invoices |
| Payment pending timeout job | Hourly | Move stale pending payments to past due |
| Past due timeout job | Hourly | Move past due subscriptions to suspended |
| Suspension timeout job | Daily | Cancel long-unpaid subscriptions |
| Provider reconciliation job | Daily | Compare local state with billing provider |
| Entitlement sync job | Hourly | Ensure access matches subscription state |

---

## 17. API Requirements

### Create Trial

```http
POST /subscriptions/trials
```

Request:

```json
{
  "workspace_id": "workspace_123",
  "plan_id": "plan_pro",
  "payment_method_id": "pm_123"
}
```

Response:

```json
{
  "subscription_id": "sub_123",
  "status": "trialing",
  "trial_end_at": "2026-06-08T00:00:00Z"
}
```

---

### Start Paid Subscription

```http
POST /subscriptions
```

Request:

```json
{
  "workspace_id": "workspace_123",
  "plan_id": "plan_pro",
  "payment_method_id": "pm_123"
}
```

---

### Cancel Subscription

```http
POST /subscriptions/{subscription_id}/cancel
```

Request:

```json
{
  "mode": "period_end",
  "reason": "customer_requested"
}
```

---

### Reactivate Subscription

```http
POST /subscriptions/{subscription_id}/reactivate
```

Request:

```json
{
  "payment_method_id": "pm_123"
}
```

---

### Get Entitlements

```http
GET /workspaces/{workspace_id}/entitlements
```

Response:

```json
{
  "workspace_id": "workspace_123",
  "access_level": "full",
  "features": [
    {
      "feature_key": "advanced_reports",
      "enabled": true
    }
  ]
}
```

---

## 18. Policy Configuration

Create a centralized subscription policy config.

```json
{
  "trial": {
    "enabled": true,
    "duration_days": 14,
    "requires_payment_method": true,
    "one_trial_per_workspace": true,
    "one_trial_per_company": true
  },
  "payment": {
    "payment_pending_timeout_days": 7,
    "retry_schedule_days": [0, 3, 6, 10, 14],
    "max_retry_attempts": 5
  },
  "past_due": {
    "timeout_days": 7,
    "access_level": "limited"
  },
  "suspension": {
    "cancel_after_days": 16,
    "access_level": "read_only"
  },
  "cancellation": {
    "default_customer_cancel_mode": "period_end",
    "admin_cancel_mode": "immediate"
  },
  "access": {
    "trialing": "full",
    "active": "full",
    "payment_pending": "full",
    "past_due": "limited",
    "suspended": "read_only",
    "canceled": "none",
    "expired": "none",
    "paused": "read_only"
  },
  "notifications": {
    "trial_ending_days_before": [7, 3, 1],
    "payment_failure_days_after": [0, 3, 6],
    "past_due_days_after": [7],
    "suspension_days_after": [14],
    "cancellation_days_after": [30]
  }
}
```

---

## 19. Implementation Phases

## Phase 1: Foundation

### Goals

- Define status model
- Create subscription tables
- Create event table
- Create basic policy config
- Implement basic subscription service

### Deliverables

- Subscription schema
- Event schema
- Subscription status enum
- Policy config
- Subscription creation endpoint
- Trial creation endpoint

### Acceptance Criteria

- A workspace can start a trial.
- A workspace can start a paid subscription.
- Subscription status is persisted.
- Every status change creates an event.

---

## Phase 2: Billing Provider Integration

### Goals

- Integrate billing provider
- Create customer records
- Create subscriptions
- Track invoices
- Track payment attempts

### Deliverables

- Billing provider adapter
- Webhook processor
- Invoice model
- Payment attempt model
- Payment success handling
- Payment failure handling

### Acceptance Criteria

- Successful payment activates subscription.
- Failed payment moves subscription to `payment_pending`.
- Webhooks are idempotent.
- Duplicate webhooks do not duplicate events.

---

## Phase 3: Trial Conversion

### Goals

- Convert trials automatically
- Handle trial expiration
- Notify users before trial end

### Deliverables

- Trial ending reminder job
- Trial conversion job
- Trial expiration handling
- Trial notification templates

### Acceptance Criteria

- Trial converts to `active` after successful payment.
- Trial moves to `payment_pending` after failed payment.
- Trial moves to `expired` if payment is not available.
- Trial ending reminders are sent on schedule.

---

## Phase 4: Payment Recovery

### Goals

- Implement dunning flow
- Retry failed payments
- Enforce payment pending timeout
- Enforce past due timeout

### Deliverables

- Payment retry job
- Payment pending timeout job
- Past due timeout job
- Notification schedule
- Admin visibility for failed payments

### Acceptance Criteria

- Failed payments are retried on schedule.
- `payment_pending` becomes `past_due` after timeout.
- `past_due` becomes `suspended` after timeout.
- Customers and admins receive notifications.

---

## Phase 5: Entitlements

### Goals

- Separate subscription status from access
- Create entitlement service
- Enforce access levels in product

### Deliverables

- Entitlement model
- Entitlement service
- Access decision API
- Feature flag integration
- Middleware or guard layer

### Acceptance Criteria

- `active` and `trialing` users receive full access.
- `past_due` users receive limited access.
- `suspended` users receive read-only or no access.
- Product code does not directly hardcode billing statuses.

---

## Phase 6: Cancellation and Reactivation

### Goals

- Support customer cancellation
- Support admin cancellation
- Support reactivation
- Support cancel-at-period-end

### Deliverables

- Cancel subscription endpoint
- Reactivate subscription endpoint
- Period-end cancellation job
- Admin cancellation flow

### Acceptance Criteria

- Customer cancellation defaults to period end.
- Admin cancellation can happen immediately.
- Reactivation requires successful payment.
- Canceled subscriptions do not renew.

---

## Phase 7: Admin Console

### Goals

- Give support and finance teams operational control
- Add audit logging for all manual actions

### Deliverables

- Subscription detail page
- Invoice history
- Payment attempt history
- Event timeline
- Manual retry action
- Extend trial action
- Extend grace period action
- Suspend action
- Reactivate action
- Cancel action

### Acceptance Criteria

- Admins can inspect complete subscription history.
- Admin actions are audited.
- High-risk actions require a reason.
- Manual overrides do not silently mutate state.

---

## Phase 8: Reconciliation and Hardening

### Goals

- Prevent billing drift
- Detect inconsistent states
- Make webhook processing resilient

### Deliverables

- Provider reconciliation job
- Dead-letter queue
- Webhook replay tool
- State consistency checks
- Alerting

### Acceptance Criteria

- Local subscription state matches billing provider state.
- Failed webhooks are visible and replayable.
- Inconsistent states generate alerts.
- Reconciliation does not break valid admin overrides.

---

## 20. State Invariants

The system must enforce these rules:

```text
A canceled subscription cannot renew.
A canceled subscription cannot become active without reactivation.
A subscription cannot be both active and canceled.
A trial cannot be active after trial_end_at.
A payment success must be idempotent.
A failed payment must not duplicate payment attempts.
A workspace cannot have multiple active subscriptions for the same product unless explicitly allowed.
Entitlements must be recalculated after every subscription status change.
Every manual override must create an audit event.
```

---

## 21. Monitoring and Alerts

Track these metrics:

```text
trial_started_count
trial_conversion_rate
payment_failed_count
payment_recovered_count
payment_pending_count
past_due_count
suspended_count
canceled_count
reactivated_count
webhook_failure_count
webhook_duplicate_count
reconciliation_mismatch_count
```

Alert on:

```text
Webhook processing failures
Spike in payment failures
Subscriptions stuck in payment_pending
Subscriptions stuck in past_due
Provider/local state mismatch
Entitlement sync failures
Unexpected cancellation spike
```

---

## 22. Testing Plan

### Unit Tests

Test:

- Status transitions
- Policy config
- Retry schedule
- Entitlement mapping
- Cancellation rules
- Reactivation rules

### Integration Tests

Test:

- Payment success webhook
- Payment failure webhook
- Duplicate webhook
- Out-of-order webhook
- Trial conversion
- Payment retry
- Suspension
- Cancellation

### End-to-End Tests

Test:

```text
Start trial → trial ends → payment succeeds → active
Start trial → trial ends → payment fails → payment_pending → past_due → suspended → canceled
Active subscription → renewal fails → payment_pending → payment succeeds → active
Active subscription → user cancels → active until period end → canceled
Suspended subscription → payment succeeds → active
```

---

## 23. Rollout Plan

### Step 1: Internal Testing

- Enable for internal workspaces only.
- Use test billing provider mode.
- Simulate webhooks.
- Validate event history.

### Step 2: Limited Beta

- Enable for selected B2B customers.
- Monitor payment failures.
- Monitor state transitions.
- Review support tickets.

### Step 3: Full Launch

- Enable for all new B2B customers.
- Keep legacy subscriptions on old system temporarily.
- Run reconciliation daily.

### Step 4: Migration

- Migrate old subscriptions into new status model.
- Generate synthetic migration events.
- Validate entitlements.
- Confirm invoice state.
- Freeze legacy billing writes.

---

## 24. Migration Plan

For each existing subscription:

1. Identify current provider status.
2. Map provider status to internal status.
3. Create internal subscription record.
4. Create current entitlement record.
5. Import current invoice state.
6. Create `subscription.migrated` event.
7. Run reconciliation check.
8. Validate workspace access.

Example mapping:

| Provider State | Internal Status |
|---|---|
| `trialing` | `trialing` |
| `active` | `active` |
| `incomplete` | `payment_pending` |
| `past_due` | `past_due` |
| `unpaid` | `suspended` |
| `canceled` | `canceled` |

---

## 25. Risks

| Risk | Mitigation |
|---|---|
| Duplicate webhooks | Idempotency keys and event deduplication |
| Out-of-order webhooks | Compare timestamps and current state |
| Incorrect access removal | Entitlement layer and audit logs |
| Customers canceled too early | Grace period and admin override |
| Trial abuse | Company-level trial eligibility checks |
| Billing provider mismatch | Daily reconciliation |
| Admin misuse | Audit logs and approval rules |
| Status sprawl | Strict status model |

---

## 26. Final Default Policy

Use this as the baseline B2B policy:

```text
Trial lasts 14 days.
Payment method is required before trial starts.
Trial converts automatically if payment succeeds.
If payment fails, subscription becomes payment_pending.
Payment pending lasts 7 days with full access.
After 7 unpaid days, subscription becomes past_due with limited access.
After 14 unpaid days, subscription becomes suspended.
After 30 unpaid days, subscription is canceled.
Customer cancellation takes effect at period end.
Admin cancellation can be immediate.
Reactivation requires successful payment.
Chargebacks suspend access immediately.
Access is controlled through entitlements.
All transitions are event-driven and audited.
```

---

## 27. Definition of Done

The B2B subscription system is complete when:

- All subscription statuses are implemented.
- All transition rules are enforced.
- Billing provider webhooks are idempotent.
- Failed payments enter recovery flow.
- Trial conversion works automatically.
- Entitlements control product access.
- Admins can override safely.
- Every lifecycle change has an audit event.
- Reconciliation detects billing drift.
- Monitoring and alerts are live.
- End-to-end tests cover the full lifecycle.
