Skip to main content

Subscription Lifecycle

Cargoman provides built-in support for subscription-based access control, designed to integrate with payment providers like Stripe.

Lifecycle States​

┌──────────┐     ┌───────────┐     ┌─────────┐
│ Active │────▶│ Suspended │────▶│ Expired │
└──────────┘ └───────────┘ └─────────┘
│ │
│ ▼
│ ┌──────────┐
└──────────▶│ Frozen │
└──────────┘

Active​

  • Customer has full access to granted packages
  • Normal operating state

Suspended​

  • Temporary block (e.g., payment failed)
  • Used during grace period before cancellation
  • Customer receives error when trying to download

Frozen​

  • Customer locked to specific versions
  • Can still download frozen versions
  • No access to newer releases

Expired​

  • Subscription fully cancelled
  • No access to any packages

Integration with Stripe​

Webhook Events​

Handle Stripe webhooks to manage customer lifecycle:

// Stripe webhook handler (pseudo-code)
match event.type {
"customer.subscription.updated" => {
if subscription.status == "past_due" {
cargoman.suspend_customer(customer_id, "Payment past due");
}
},
"customer.subscription.deleted" => {
cargoman.freeze_customer(customer_id, current_versions);
// or: cargoman.expire_customer(customer_id);
},
"invoice.paid" => {
cargoman.reactivate_customer(customer_id);
}
}

Grace Period​

Implement a grace period for failed payments:

  1. Payment fails -> Suspend customer
  2. Wait 7-14 days for retry
  3. If paid -> Reactivate
  4. If not paid -> Freeze or expire

Version Freezing​

When freezing a customer, specify which versions they can access:

curl -X POST https://packages.example.com/api/v1/customers/cust_xyz789/freeze \
-H "Authorization: Bearer $ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"versions": [
{"package": "vendor/core", "version": "2.5.0"},
{"package": "vendor/addon", "version": "1.2.0"}
]
}'

The customer can still download these specific versions but not newer ones.

Typical Flows​

New Customer​

  1. Customer signs up and pays
  2. Create customer in Cargoman with external_id = Stripe customer ID
  3. Grant package access
  4. Customer configures Composer

Payment Failure​

  1. Stripe sends invoice.payment_failed webhook
  2. Suspend customer with reason
  3. Customer sees error on composer install
  4. After grace period, freeze or expire

Subscription Renewal​

  1. Stripe sends invoice.paid webhook
  2. If suspended, reactivate customer
  3. Customer access restored

Cancellation​

  1. Customer cancels in your dashboard
  2. Stripe sends customer.subscription.deleted
  3. Freeze customer to current versions
  4. Customer can still use existing code

API Reference​

# Suspend
POST /api/v1/customers/{id}/suspend
Body: {"reason": "Payment failed"}

# Reactivate
POST /api/v1/customers/{id}/reactivate

# Freeze
POST /api/v1/customers/{id}/freeze
Body: {"versions": [...]}

# Get customer status
GET /api/v1/customers/{id}

Next Steps​