Subscription Management Endpoints Index

Subscription Management Endpoints

GET /api/subscriptions

List all subscriptions with filtering and pagination (requires authentication)

Headers:

Authorization: Bearer ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqr...

Query Parameters:

Response (200 OK):

{
    "data": [
        {
            "id": 1,
            "userId": 1,
            "email": "user@example.com",
            "username": "user123",
            "plan": {
                "id": 1,
                "stripePriceId": "price_...",
                "name": "Pro Plan",
                "interval": "month",
                "amount": 999,
                "currency": "usd",
                "trialPeriodDays": 14,
                "isActive": true,
                "createdAt": "2023-01-15T08:30:00Z",
                "updatedAt": null
            },
            "status": "active",
            "currentPeriodStart": "2023-06-01T00:00:00Z",
            "currentPeriodEnd": "2023-07-01T00:00:00Z",
            "trialStart": "2023-06-01T00:00:00Z",
            "trialEnd": "2023-06-15T00:00:00Z",
            "cancelAtPeriodEnd": false,
            "canceledAt": null,
            "createdAt": "2023-06-01T00:00:00Z",
            "updatedAt": null,
            "promotion": {
                "id": 5,
                "name": "Summer Sale 2023",
                "coupon": {
                    "id": 3,
                    "type": "DISC",
                    "name": "Discount Percentage",
                    "percentOff": 20,
                    "trialDays": null
                }
            }
        }
        // Additional subscription objects...
    ],
    "total": 42
}

Notes:

GET /api/subscriptions/me

Get the current user's subscription (requires authentication)

Headers:

Authorization: Bearer ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqr...

Response (200 OK):

{
    "id": 1,
    "userId": 1,
    "email": "user@example.com",
    "username": "user123",
    "plan": {
        "id": 1,
        "stripePriceId": "price_...",
        "name": "Pro Plan",
        "interval": "month",
        "amount": 999,
        "currency": "usd",
        "trialPeriodDays": 14,
        "isActive": true,
        "createdAt": "2023-01-15T08:30:00Z",
        "updatedAt": null
    },
    "status": "active",
    "currentPeriodStart": "2023-06-01T00:00:00Z",
    "currentPeriodEnd": "2023-07-01T00:00:00Z",
    "trialStart": "2023-06-01T00:00:00Z",
    "trialEnd": "2023-06-15T00:00:00Z",
    "cancelAtPeriodEnd": false,
    "canceledAt": null,
    "createdAt": "2023-06-01T00:00:00Z",
    "updatedAt": null,
    "promotion": {
        "id": 5,
        "name": "Summer Sale 2023",
        "coupon": {
            "id": 3,
            "type": "DISC",
            "name": "Discount Percentage",
            "percentOff": 20,
            "trialDays": null
        }
    }
}
GET /api/subscriptions/plans

List all available subscription plans (requires authentication)

Headers:

Authorization: Bearer ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqr...

Query Parameters:

Response (200 OK):

{
    "data": [
        {
            "id": 1,
            "stripePriceId": "price_...",
            "name": "Basic Plan",
            "interval": "month",
            "amount": 499,
            "currency": "usd",
            "trialPeriodDays": 14,
            "isActive": true,
            "createdAt": "2023-01-15T08:30:00Z",
            "updatedAt": null
        },
        {
            "id": 2,
            "stripePriceId": "price_...",
            "name": "Pro Plan",
            "interval": "month",
            "amount": 999,
            "currency": "usd",
            "trialPeriodDays": 14,
            "isActive": true,
            "createdAt": "2023-01-15T08:30:00Z",
            "updatedAt": null
        }
        // Additional plan objects...
    ],
    "total": 5
}

Notes:

GET /api/subscriptions/verify-payment

Verify payment status for a subscription using payment intent ID (requires authentication)

Headers:

Authorization: Bearer ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqr...

Query Parameters:

Response (200 OK):

{
    "id": 1,
    "userId": 1,
    "email": "user@example.com",
    "username": "user123",
    "plan": {
        "id": 1,
        "stripePriceId": "price_...",
        "name": "Pro Plan",
        "interval": "month",
        "amount": 999,
        "currency": "usd",
        "trialPeriodDays": 14,
        "isActive": true,
        "createdAt": "2023-01-15T08:30:00Z",
        "updatedAt": null
    },
    "status": "active",
    "currentPeriodStart": "2023-06-01T00:00:00Z",
    "currentPeriodEnd": "2023-07-01T00:00:00Z",
    "trialStart": null,
    "trialEnd": null,
    "cancelAtPeriodEnd": false,
    "canceledAt": null,
    "createdAt": "2023-06-01T00:00:00Z",
    "updatedAt": "2023-06-15T00:00:00Z",
    "promotion": null
}

Error Responses:

{
    "message": "Payment intent ID is required"
}

{
    "message": "Subscription not found or could not be updated"
}
GET /api/subscriptions/verify-setup

Verify setup intent status for a subscription (requires authentication)

Headers:

Authorization: Bearer ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqr...

Query Parameters:

Response (200 OK):

{
    "id": 1,
    "userId": 1,
    "email": "user@example.com",
    "username": "user123",
    "plan": {
        "id": 1,
        "stripePriceId": "price_...",
        "name": "Pro Plan",
        "interval": "month",
        "amount": 999,
        "currency": "usd",
        "trialPeriodDays": 14,
        "isActive": true,
        "createdAt": "2023-01-15T08:30:00Z",
        "updatedAt": null
    },
    "status": "active",
    "currentPeriodStart": "2023-06-01T00:00:00Z",
    "currentPeriodEnd": "2023-07-01T00:00:00Z",
    "trialStart": null,
    "trialEnd": null,
    "cancelAtPeriodEnd": false,
    "canceledAt": null,
    "createdAt": "2023-06-01T00:00:00Z",
    "updatedAt": "2023-06-15T00:00:00Z",
    "promotion": null
}

Error Responses:

{
    "message": "Setup intent ID is required"
}

{
    "message": "Subscription not found or could not be updated"
}
POST /api/subscriptions/change-plan

Change the user's subscription to a different plan (requires authentication)

Headers:

Authorization: Bearer ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqr...

Request Body:

{
    "planId": 2,
    "prorationBehavior": "create_prorations"  // Optional: "create_prorations", "none", or "always_invoice"
}

Response (200 OK):

{
    "message": "Subscription plan changed successfully",
    "subscription": {
        "id": 1,
        "userId": 1,
        "email": "user@example.com",
        "username": "user123",
        "plan": {
            "id": 2,
            "stripePriceId": "price_...",
            "name": "Premium Plan",
            "interval": "month",
            "amount": 1999,
            "currency": "usd",
            "trialPeriodDays": 0,
            "isActive": true,
            "createdAt": "2023-01-15T08:30:00Z",
            "updatedAt": null
        },
        "status": "active",
        "currentPeriodStart": "2023-06-01T00:00:00Z",
        "currentPeriodEnd": "2023-07-01T00:00:00Z",
        "trialStart": null,
        "trialEnd": null,
        "cancelAtPeriodEnd": false,
        "canceledAt": null,
        "createdAt": "2023-06-01T00:00:00Z",
        "updatedAt": "2023-06-15T00:00:00Z",
        "promotion": null
    }
}

Error Responses:

{
    "message": "Plan ID is required"
}

{
    "message": "You don't have an active subscription"
}

{
    "message": "You are already subscribed to this plan"
}

{
    "message": "The selected plan is not available"
}
POST /api/subscriptions/change-plan-with-payment-method

Change the user's subscription to a different plan while updating payment method (requires authentication)

Headers:

Authorization: Bearer ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqr...

Request Body:

{
    "planId": 2,
    "paymentMethodId": "pm_1234567890",
    "prorationBehavior": "create_prorations"  // Optional: "create_prorations", "none", or "always_invoice"
}

Response (200 OK):

{
    "requiresAction": true,
    "setupIntentClientSecret": "seti_1RJYc0PFpKHu6YD8quMd7VH8_secret_...",
    "setupIntentId": "seti_1RJYc0PFpKHu6YD8quMd7VH8",
    "planId": 2,
    "prorationBehavior": "create_prorations"
}

Error Responses:

{
    "message": "Plan ID is required"
}

{
    "message": "Payment method ID is required"
}

{
    "message": "You don't have an active subscription"
}

{
    "message": "There was a problem setting up the payment method"
}
POST /api/subscriptions/confirm-change-plan

Confirm plan change after setup intent is completed (requires authentication)

Headers:

Authorization: Bearer ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqr...

Request Body:

{
    "setupIntentId": "seti_1RJYc0PFpKHu6YD8quMd7VH8",
    "planId": 2,
    "prorationBehavior": "create_prorations"  // Optional: "create_prorations", "none", or "always_invoice"
}

Response (200 OK):

{
    "message": "Subscription plan and payment method updated successfully",
    "subscription": {
        "id": 1,
        "userId": 1,
        "email": "user@example.com",
        "username": "user123",
        "plan": {
            "id": 2,
            "stripePriceId": "price_...",
            "name": "Premium Plan",
            "interval": "month",
            "amount": 1999,
            "currency": "usd",
            "trialPeriodDays": 0,
            "isActive": true,
            "createdAt": "2023-01-15T08:30:00Z",
            "updatedAt": null
        },
        "status": "active",
        "currentPeriodStart": "2023-06-01T00:00:00Z",
        "currentPeriodEnd": "2023-07-01T00:00:00Z",
        "trialStart": null,
        "trialEnd": null,
        "cancelAtPeriodEnd": false,
        "canceledAt": null,
        "createdAt": "2023-06-01T00:00:00Z",
        "updatedAt": "2023-06-15T00:00:00Z",
        "promotion": null
    }
}

Error Responses:

{
    "message": "Setup intent ID is required"
}

{
    "message": "Plan ID is required"
}

{
    "message": "Setup intent is not complete. Current status: requires_payment_method"
}

{
    "message": "Failed to attach payment method"
}
POST /api/subscriptions/create-free-trial

Create a free trial subscription without requiring payment method (requires authentication)

Headers:

Authorization: Bearer ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqr...

Request Body:

{
    "priceId": "price_H5ggYwtDq4fbrJ",
    "trialPeriodDays": 14  // Optional: Defaults to 14 days if not specified
}

Response (200 OK):

{
    "message": "Free trial subscription created successfully",
    "subscription": {
        "id": 1,
        "userId": 1,
        "email": "user@example.com",
        "username": "user123",
        "plan": {
            "id": 1,
            "stripePriceId": "price_H5ggYwtDq4fbrJ",
            "name": "Pro Plan",
            "interval": "month",
            "amount": 999,
            "currency": "usd",
            "trialPeriodDays": 14,
            "isActive": true,
            "createdAt": "2023-01-15T08:30:00Z",
            "updatedAt": null
        },
        "status": "trialing",
        "currentPeriodStart": "2023-06-01T00:00:00Z",
        "currentPeriodEnd": "2023-07-01T00:00:00Z",
        "trialStart": "2023-06-01T00:00:00Z",
        "trialEnd": "2023-06-15T00:00:00Z",
        "cancelAtPeriodEnd": false,
        "canceledAt": null,
        "createdAt": "2023-06-01T00:00:00Z",
        "updatedAt": null,
        "promotion": null
    },
    "trialEnd": "2023-06-15T00:00:00Z"
}

Error Responses:

{
    "message": "User already has an active subscription"
}

{
    "message": "Price ID is required"
}

{
    "message": "User not found"
}

{
    "message": "Subscription plan not found"
}
POST /api/subscriptions/create-with-payment-method

Create a subscription with payment method ID (deferred payment flow) (requires authentication)

Headers:

Authorization: Bearer ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqr...

Request Body:

{
    "priceId": "price_H5ggYwtDq4fbrJ",
    "paymentMethodId": "pm_1234567890",
    "trialPeriodDays": 14  // Optional: Number of trial days
}

Response (200 OK):

{
    "subscriptionId": "sub_1RJYc0PFpKHu6YD8quMd7VH8",
    "type": "payment",
    "clientSecret": "cs_test_..."
}

Alternative Response (Setup Flow):

{
    "subscriptionId": "sub_1RJYc0PFpKHu6YD8quMd7VH8",
    "type": "setup",
    "clientSecret": "seti_1RJYc0PFpKHu6YD8quMd7VH8_secret_..."
}

Error Responses:

{
    "message": "Price ID is required"
}

{
    "message": "Payment method ID is required"
}

{
    "message": "User already has an active subscription"
}

{
    "message": "Subscription plan not found"
}

Notes:

POST /api/subscriptions/resume

Resume a subscription that was previously scheduled for cancellation (requires authentication)

Headers:

Authorization: Bearer ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqr...

Response (200 OK):

{
    "id": 1,
    "userId": 1,
    "email": "user@example.com",
    "username": "user123",
    "plan": {
        "id": 1,
        "stripePriceId": "price_...",
        "name": "Pro Plan",
        "interval": "month",
        "amount": 999,
        "currency": "usd",
        "trialPeriodDays": 14,
        "isActive": true,
        "createdAt": "2023-01-15T08:30:00Z",
        "updatedAt": null
    },
    "status": "active",
    "currentPeriodStart": "2023-06-01T00:00:00Z",
    "currentPeriodEnd": "2023-07-01T00:00:00Z",
    "trialStart": null,
    "trialEnd": null,
    "cancelAtPeriodEnd": false,
    "canceledAt": null,
    "createdAt": "2023-06-01T00:00:00Z",
    "updatedAt": "2023-06-15T00:00:00Z",
    "promotion": null
}

Error Responses:

{
    "message": "Subscription not found or could not be resumed"
}

{
    "message": "Failed to resume subscription",
    "error": "Cannot resume subscription because it is already fully canceled"
}
POST /api/subscriptions/sync-plans

Sync subscription plans with Stripe (requires authentication and admin privileges)

Headers:

Authorization: Bearer ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqr...

Response (200 OK):

{
    "message": "Successfully synchronized 8 subscription plans with Stripe",
    "syncedPlans": 8
}

Error Responses:

{
    "message": "Access denied. Admin privileges required."
}
POST /api/subscriptions/update-payment-method

Update the payment method for a user's subscription (requires authentication)

Headers:

Authorization: Bearer ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqr...

Request Body:

{
    "paymentMethodId": "pm_1234567890"
}

Response (200 OK):

{
    "success": true,
    "message": "Payment method updated successfully",
    "subscription": {
        "id": 1,
        "userId": 1,
        "email": "user@example.com",
        "username": "user123",
        "plan": {
            "id": 1,
            "stripePriceId": "price_...",
            "name": "Pro Plan",
            "interval": "month",
            "amount": 999,
            "currency": "usd",
            "trialPeriodDays": 14,
            "isActive": true,
            "createdAt": "2023-01-15T08:30:00Z",
            "updatedAt": null
        },
        "status": "active",
        "currentPeriodStart": "2023-06-01T00:00:00Z",
        "currentPeriodEnd": "2023-07-01T00:00:00Z",
        "trialStart": null,
        "trialEnd": null,
        "cancelAtPeriodEnd": false,
        "canceledAt": null,
        "createdAt": "2023-06-01T00:00:00Z",
        "updatedAt": "2023-06-15T00:00:00Z",
        "promotion": null
    }
}

Error Responses:

{
    "success": false,
    "message": "Payment method ID is required"
}

{
    "success": false,
    "message": "Failed to update payment method",
    "error": {
        "type": "card_error",
        "message": "Your card was declined.",
        "code": "card_declined",
        "decline_code": "generic_decline"
    }
}

Notes:

PUT /api/subscriptions/me

Update the current user's subscription (requires authentication)

Headers:

Authorization: Bearer ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqr...
x-csrf-token: a8d7f9c6e5b4a3c2d1e0f9a8d7f6c5b4a3

Request Body:

{
    "planId": 2,
    "paymentMethodId": "pm_1234567890"  // Optional: New payment method
}

Response (200 OK):

{
    "id": 1,
    "userId": 1,
    "email": "user@example.com",
    "username": "user123",
    "plan": {
        "id": 2,
        "stripePriceId": "price_...",
        "name": "Premium Plan",
        "interval": "month",
        "amount": 1999,
        "currency": "usd",
        "trialPeriodDays": 0,
        "isActive": true,
        "createdAt": "2023-01-15T08:30:00Z",
        "updatedAt": null
    },
    "status": "active",
    "currentPeriodStart": "2023-06-01T00:00:00Z",
    "currentPeriodEnd": "2023-07-01T00:00:00Z",
    "trialStart": null,
    "trialEnd": null,
    "cancelAtPeriodEnd": false,
    "canceledAt": null,
    "createdAt": "2023-06-01T00:00:00Z",
    "updatedAt": "2023-06-15T00:00:00Z",
    "promotion": null
}
DELETE /api/subscriptions/me

Cancel the current user's subscription (requires authentication)

Headers:

Authorization: Bearer ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqr...

Query Parameters:

Response (200 OK):

{
    "id": 1,
    "userId": 1,
    "email": "user@example.com",
    "username": "user123",
    "plan": {
        "id": 1,
        "stripePriceId": "price_...",
        "name": "Pro Plan",
        "interval": "month",
        "amount": 999,
        "currency": "usd",
        "trialPeriodDays": 14,
        "isActive": true,
        "createdAt": "2023-01-15T08:30:00Z",
        "updatedAt": null
    },
    "status": "active",
    "currentPeriodStart": "2023-06-01T00:00:00Z",
    "currentPeriodEnd": "2023-07-01T00:00:00Z",
    "trialStart": null,
    "trialEnd": null,
    "cancelAtPeriodEnd": true,
    "canceledAt": "2023-06-15T00:00:00Z",
    "createdAt": "2023-06-01T00:00:00Z",
    "updatedAt": "2023-06-15T00:00:00Z",
    "promotion": null
}