ReachLMS REST API

Backend API for Canvas LMS sub-account provisioning with Stripe billing integration.

Authentication: Most endpoints require a JWT Bearer token in the Authorization header. Authorization: Bearer <access_token>

Stripe Billing

Endpoints for managing Stripe customers, subscriptions, and billing.

Create Stripe Customer

Creates or retrieves a Stripe customer. Supports both authenticated and unauthenticated requests.

POST

Endpoint: /api/stripe/create-stripe-customer

Authentication optional (uses JWT if present, otherwise requires email in body)

Request Body:

{
    "name": "John Doe",
    "email": "[email protected]"
}

Success Response (Created): 201

{
    "message": "Customer Created",
    "customer_id": "cus_abc123"
}

Success Response (Found): 200

{
    "message": "Customer Found",
    "customer_id": "cus_abc123"
}

Get Stripe Customer

Retrieve Stripe customer information.

POST

Endpoint: /api/stripe/stripe-customer

Authentication optional (uses JWT if present, otherwise requires email in body)

Request Body (unauthenticated):

{
    "email": "[email protected]"
}

Success Response: 200

{
    "message": "Customer found",
    "customer_id": "cus_abc123",
    "status": 200
}

Not Found Response: 400

{
    "status": "Stripe customer not found"
}

Create Subscription Session

Create a Stripe subscription with payment intent. Handles legacy users with extended trials.

POST

Endpoint: /api/stripe/create-subscription-session

Authentication optional (uses JWT if present, otherwise requires customer_id or email)

Request Body:

{
    "price_id": "price_abc123",
    "customer_id": "cus_abc123",
    "email": "[email protected]"
}

Provide either customer_id (preferred) or email for unauthenticated requests.

Success Response: 200

{
    "subscriptionId": "sub_abc123",
    "clientSecret": "pi_abc123_secret_xyz",
    "legacy": false,
    "isFree": false
}

Get Products

Retrieve all available subscription products grouped by billing interval.

GET

Endpoint: /api/stripe/products

Authentication optional (authenticated users get price_id and product_id)

Request Body: None

Success Response: 200

{
    "month": [
        {
            "name": "Starter",
            "currency": "usd",
            "description": "For small teams",
            "cost": 1500,
            "user_count": 10,
            "interval": "month",
            "price_id": "price_abc123",
            "product_id": "prod_xyz789"
        }
    ],
    "year": [
        {
            "name": "Starter",
            "currency": "usd",
            "description": "For small teams",
            "cost": 15000,
            "user_count": 10,
            "interval": "year",
            "price_id": "price_def456",
            "product_id": "prod_xyz789"
        }
    ],
    "metered": [],
    "free": []
}

Get Product by Name

Retrieve a specific product by name and optionally filter by billing interval.

POST

Endpoint: /api/stripe/product

Authentication optional

Request Body:

{
    "name": "Starter",
    "interval": "month"
}

Success Response: 200

{
    "name": "Starter",
    "currency": "usd",
    "description": "For small teams",
    "cost": 1500,
    "user_count": 10,
    "interval": "month",
    "price_id": "price_abc123",
    "product_id": "prod_xyz789"
}

Not Found Response: 404

{
    "error": "Product not found"
}

Register Subscription

Register a subscription after successful payment. Creates or retrieves CanvasUser and CanvasAccount, creates metered overage subscription, and links everything in a single atomic transaction.

POST

Endpoint: /api/stripe/register-subscription

Requires JWT access token

Request Body:

{
    "email": "[email protected]",
    "sis_user_id": "user-john-abc123",
    "account_name": "Acme Corp Training",
    "account_sis_id": "acme-corp-123",
    "subscription_id": "sub_abc123",
    "price_id": "price_xyz789",
    "payment_method_id": "pm_card_visa"
}

All fields except payment_method_id are required. If CanvasUser or CanvasAccount don't exist, they will be created automatically.

Success Response: 201

{
    "message": "Subscription registered successfully",
    "subscription_id": "sub_abc123",
    "metered_subscription_id": "sub_meter456",
    "already_existed": false
}

Already Registered Response: 200

{
    "message": "Subscription already registered",
    "already_existed": true
}

Error Response (Missing Fields): 400

{
    "error": "Missing required fields: sis_user_id, account_sis_id"
}

Get User Subscriptions

Retrieve all active subscriptions for the authenticated user with product and metering details.

GET

Endpoint: /api/stripe/user-subscriptions

Requires JWT access token

Request Body: None

Success Response: 200

[
    {
        "id": 1,
        "subscription": "Starter",
        "interval": "month",
        "currency": "usd",
        "cost": 1500,
        "userlimit": 10,
        "activeusers": "Acme Corp Training",
        "is_admin": "[email protected]",
        "subaccount": "Acme Corp Training",
        "start_date": "2025-01-30 10:00:00",
        "price_id": "price_abc123",
        "user_over": 0,
        "meter_name": "User Overage",
        "dollar_rate": 150
    }
]

Update Subscription

Change a subscription to a different plan. Updates both Stripe and local database.

PUT

Endpoint: /api/stripe/update-subscription

Requires JWT access token

Request Body:

{
    "subscription_id": 1,
    "price_id": "price_newplan789"
}

subscription_id is the local database ID, not the Stripe subscription ID.

Success Response: 200

{
    "status": "success",
    "message": "Subscription updated successfully",
    "subscription_id": "sub_abc123",
    "new_price_id": "price_newplan789",
    "product_name": "Professional"
}

Cancel Subscription

Cancel a subscription. Pauses billing collection and schedules Canvas account for deletion in 30 days.

PUT

Endpoint: /api/stripe/cancel-subscription

Requires JWT access token

Request Body:

{
    "sub_id": 1
}

sub_id is the local database subscription ID.

Success Response: 200

{
    "status": "success",
    "message": "Subscription cancelled successfully",
    "cancel_date": "2025-03-01T10:00:00+00:00",
    "main_subscription_id": "sub_abc123",
    "main_subscription_paused": true,
    "metered_subscription_id": "sub_meter456",
    "metered_subscription_paused": true
}