This plugin controls whether the Trakli webservice operates in free or paid mode. It manages the subscription functionality, pricing plans, and feature access based on the current mode.
- Toggle between free and paid service modes
- Configurable pricing plans when in paid mode
- Simple API endpoints for checking service status and plans
- Environment-based configuration
-
Clone or download this plugin into your
plugins/clouddirectory. -
Publish the configuration file:
php artisan vendor:publish --tag=cloud-config
Or manually copy the config file:
cp plugins/cloud/config/cloudplans.php config/cloudplans.php
-
The configuration will be available at
config/cloudplans.phpwhere you can customize the settings. -
If you modify the configuration, clear the config cache:
php artisan config:clear php artisan cache:clear
-
Free Mode (default):
- All features are available without payment
- No subscription required
- Set
CLOUD_FREE_PLAN_ENABLED=true
-
Paid Mode:
- Requires subscription after trial period
- Configure pricing and plans
- Set
CLOUD_FREE_PLAN_ENABLED=false
# Enable/disable free mode (when true, all features are free)
CLOUD_FREE_PLAN_ENABLED=true
# Pricing (in cents, only used when FREE_PLAN_ENABLED=false)
CLOUD_PLAN_MONTHLY_PRICE=500 # $5.00
CLOUD_PLAN_YEARLY_PRICE=5000 # $50.00 (about 17% off monthly)Currently supported regions:
- US (United States)
- EU (Europe)
- UK (United Kingdom)
All regions use USD as the currency.
The GET /api/cloud/plans endpoint retrieves available subscription plans. The response structure changes based on whether the optional region query parameter is provided.
When the region parameter is included (e.g., ?region=us), the API returns a detailed response for that single region.
Example Request:
GET /api/cloud/plans?region=usExample Response (region=us):
{
"success": true,
"message": "Operation successful",
"data": {
"overview": { /* ... */ },
"region": "United States",
"currency": "USD",
"trial_days": 3,
"free_plan_enabled": false,
"plans": [
{
"id": "monthly",
"name": "Monthly",
"interval": "month",
"features": [/* ... */],
"cta": { /* ... */ },
"price": 5.00,
"price_formatted": "$5.00"
},
{
"id": "yearly",
"name": "Yearly",
"interval": "year",
"features": [/* ... */],
"cta": { /* ... */ },
"price": 50.00,
"price_formatted": "$50.00"
}
]
}
}When the region parameter is omitted, the API returns a consolidated response containing base plan information and a breakdown of pricing for all available regions. This avoids data duplication.
Example Request:
GET /api/cloud/plansExample Response (All Regions):
{
"success": true,
"message": "Operation successful",
"data": {
"overview": { /* ... */ },
"trial_days": 3,
"free_plan_enabled": false,
"plans": [
{
"id": "monthly",
"name": "Monthly",
"interval": "month",
"features": [/* ... */],
"cta": { /* ... */ }
},
{
"id": "yearly",
"name": "Yearly",
"interval": "year",
"features": [/* ... */],
"cta": { /* ... */ }
}
],
"regions": {
"us": {
"name": "United States",
"currency": "USD",
"prices": {
"monthly": {
"price": 5.00,
"price_formatted": "$5.00"
},
"yearly": {
"price": 50.00,
"price_formatted": "$50.00"
}
}
},
"eu": {
"name": "Europe",
"currency": "EUR",
"prices": {
"monthly": {
"price": 5.00,
"price_formatted": "€5.00"
},
"yearly": {
"price": 50.00,
"price_formatted": "€50.00"
}
}
}
}
}
}GET /api/cloud/benefitsExample Response:
{
"overview": {
"title": "Why Create a Trakli Cloud Account?",
"description": "..."
},
"benefits": [
{
"title": "Access Anywhere",
"description": "..."
}
],
"trial_days": 3
}Billing is provided by whilesmart/entitlements-cashier, the Cashier adapter for
whilesmart/eloquent-entitlements. The plugin owns the plan definitions and the
checkout endpoint; the packages own the Stripe customer, the subscription
tables, and the webhook that mirrors Stripe state locally.
Set the Stripe credentials and point a Stripe webhook at /stripe/webhook:
STRIPE_KEY=your-publishable-key-here
STRIPE_SECRET=your-secret-key-here
STRIPE_WEBHOOK_SECRET=your-webhook-signing-secret-here
ENTITLEMENTS_CASHIER_SUCCESS_URL=https://app.example.com/billing/success
ENTITLEMENTS_CASHIER_CANCEL_URL=https://app.example.com/billing/cancelThen mirror the configured plans into the entitlements tables and create a Stripe price for each:
php artisan migrate
php artisan cloud:sync-plansA plan is created per plan and region, keyed {plan}-{region} (monthly-us,
yearly-eu), because a Stripe price carries a single currency. The price comes
from the amount in config/cloudplans.php, so no Stripe price id is kept by
hand; re-run the command after changing an amount and a new Stripe price is
created for it.
POST /api/v1/cloud/checkout takes plan and region and returns the Stripe
Checkout URL. Where Stripe returns the customer afterwards is configured above,
not sent by the client.
Each plan carries three machine-readable keys alongside its marketing copy:
feature_keys (what the plan unlocks), limits (max_wallets,
max_categories, where null means unlimited) and token_allowance (the AI
meter). cloud:sync-plans copies all three onto the plan rows, so the gate
reads the database, not the config, at request time.
With this plugin enabled the core gate is answered from the owner's plan rather
than allowing everything. An owner with no subscription is treated as being on
the free plan, so their limits apply instead of reading as unlimited. Setting
CLOUD_FREEMODE_ENABLED=true leaves the permissive default in place and turns
enforcement off entirely.
Gate a route on a feature with the feature middleware, which answers 402 with
the reason the plan does not cover it:
Route::middleware('feature:plaid')->group(function () {
// ...
});The AI token allowance on each plan is counted against the token usage core already records, so the plugin keeps no counter of its own and the two cannot drift apart. Usage is measured from the start of the calendar month, whatever the billing interval, so a yearly plan gets its allowance back every month. Once an owner is over the allowance, a chat turn answers with a quota message instead of calling the model.
Edit config/cloudplans.php to modify:
- Plan features
- Benefits
- Trial period
- Region settings
- Add a new entry to the
regionsarray inconfig/cloudplans.php - The region key should be a 2-3 letter code (e.g., 'ca' for Canada)
- Set the name and currency for the region
Run the test suite:
php artisan testThis plugin is open-source software licensed under the MIT License.