HEX
Server: LiteSpeed
System: Linux s1049.use1.mysecurecloudhost.com 4.18.0-477.27.2.lve.el8.x86_64 #1 SMP Wed Oct 11 12:32:56 UTC 2023 x86_64
User: xedaptot (3356)
PHP: 8.3.31
Disabled: NONE
Upload Files
File: /home/xedaptot/ai.naniguide.com/routes/api.php
<?php

use Illuminate\Http\Request;

/*
|--------------------------------------------------------------------------
| API Routes
|--------------------------------------------------------------------------
|
| Here is where you can register API routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| is assigned the "api" middleware group. Enjoy building your API!
|
*/

Route::group(['namespace' => '\App\Http\Controllers\Api', 'prefix' => 'v1', 'middleware' => ['auth:api']], function () {
    // Scalable FileBrowser backend — see /home/nghi/scalable-filemanager/README.md
    Route::prefix('filemanager')->group(function () {
        Route::get('list',         'FileManagerApiController@list')->name('api.filemanager.list');
        Route::post('upload',      'FileManagerApiController@upload')->name('api.filemanager.upload');
        Route::delete('delete',    'FileManagerApiController@delete')->name('api.filemanager.delete');
        Route::patch('rename',     'FileManagerApiController@rename')->name('api.filemanager.rename');
        Route::get('view',         'FileManagerApiController@view')->name('api.filemanager.view');
        Route::post('create-file', 'FileManagerApiController@createFile')->name('api.filemanager.create-file');
    });

    // Dedicated endpoint hosting DirectoryAssetManager (base_path()). Admin-only.
    Route::prefix('app-directory')->group(function () {
        Route::get('list',         'AppDirectoryApiController@list')->name('api.app-directory.list');
        Route::post('upload',      'AppDirectoryApiController@upload')->name('api.app-directory.upload');
        Route::delete('delete',    'AppDirectoryApiController@delete')->name('api.app-directory.delete');
        Route::patch('rename',     'AppDirectoryApiController@rename')->name('api.app-directory.rename');
        Route::post('create-file', 'AppDirectoryApiController@createFile')->name('api.app-directory.create-file');
    });

    //
    Route::get('', function () {
        return \Response::json(\Auth::guard('api')->user());
    });

    // Simple authentication
    Route::get('me', function () {
        return \Response::json(\Auth::guard('api')->user());
    });

    // Identity + instance metadata — used by support tooling (e.g. `php artisan
    // remote:upgrade --min-version=X`) to read current Acelle version cheaply
    // without running an upgrade dry-run. Lives in core so it works on a vanilla
    // install — no acelle/console plugin required.
    Route::get('whoami', 'WhoamiController')->name('api.whoami');

    // List
    Route::delete('lists/{uid}', 'MailListController@delete');
    Route::post('lists/{uid}/add-field', 'MailListController@addField');
    Route::resource('lists', 'MailListController')->names([
        'index' => 'api.lists.index',
        'create' => 'api.lists.create',
        'store' => 'api.lists.store',
        'show' => 'api.lists.show',
        'edit' => 'api.lists.edit',
        'update' => 'api.lists.update',
        'destroy' => 'api.lists.destroy',
    ]);

    // Campaign
    Route::delete('campaigns/{uid}', 'CampaignController@delete');
    Route::post('campaigns/{uid}/pause', 'CampaignController@pause');
    Route::post('campaigns/{uid}/run', 'CampaignController@run');
    Route::post('campaigns/{uid}/resume', 'CampaignController@resume');
    Route::resource('campaigns', 'CampaignController')->names([
        'index' => 'api.campaigns.index',
        'create' => 'api.campaigns.create',
        'store' => 'api.campaigns.store',
        'show' => 'api.campaigns.show',
        'edit' => 'api.campaigns.edit',
        'update' => 'api.campaigns.update',
        'destroy' => 'api.campaigns.destroy',
    ]);
    Route::get('campaigns/{uid}/tracking-log/download', 'CampaignController@downloadTrackingLog');
    Route::get('campaigns/{uid}/open-log/download', 'CampaignController@downloadOpenLog');
    Route::get('campaigns/{uid}/click-log/download', 'CampaignController@downloadClickLog');
    Route::get('campaigns/{uid}/bounce-log/download', 'CampaignController@downloadBounceLog');
    Route::get('campaigns/{uid}/feedback-log/download', 'CampaignController@downloadFeedbackLog');
    Route::get('campaigns/{uid}/unsubscribe-log/download', 'CampaignController@downloadUnsubscribeLog');

    // Subscriber
    Route::patch('lists/{list_uid}/subscribers/email/{email}/unsubscribe', 'SubscriberController@unsubscribeEmail');
    Route::post('subscribers/{id}/add-tag', 'SubscriberController@addTag');
    Route::post('subscribers/{id}/remove-tag', 'SubscriberController@removeTag');
    Route::get('subscribers/email/{email}', 'SubscriberController@showByEmail');
    Route::patch('lists/{list_uid}/subscribers/{id}/subscribe', 'SubscriberController@subscribe');
    Route::patch('lists/{list_uid}/subscribers/{id}/unsubscribe', 'SubscriberController@unsubscribe');
    Route::delete('subscribers/{id}', 'SubscriberController@delete');

    Route::resource('subscribers', 'SubscriberController')->names([
        'index' => 'api.subscribers.index',
        'create' => 'api.subscribers.create',
        'store' => 'api.subscribers.store',
        'show' => 'api.subscribers.show',
        'edit' => 'api.subscribers.edit',
        'update' => 'api.subscribers.update',
        'destroy' => 'api.subscribers.destroy',
    ]);

    // Bulk subscriber endpoints. Sync path here; async + status polling +
    // cancel sit on SubscribersBulkAsyncController. Write endpoints are
    // throttled (60/min) so a misbehaving integration can't lap the queue
    // worker or starve the DB; GET endpoints stay unthrottled because they
    // are typically polled at 1-2 Hz from job-status dashboards.
    Route::middleware('throttle:60,1')->group(function () {
        Route::post('lists/{list_uid}/subscribers/bulk', 'SubscribersBulkController@store')
            ->name('api.lists.subscribers.bulk');

        Route::post('lists/{list_uid}/subscribers/bulk/async', 'SubscribersBulkAsyncController@store')
            ->name('api.lists.subscribers.bulk_async');

        Route::delete('import-jobs/{job_uid}', 'SubscribersBulkAsyncController@destroy')
            ->name('api.import_jobs.destroy');
    });

    Route::get('lists/{list_uid}/import-jobs', 'SubscribersBulkAsyncController@indexForList')
        ->name('api.lists.import_jobs.index');
    Route::get('import-jobs/{job_uid}', 'SubscribersBulkAsyncController@show')
        ->name('api.import_jobs.show');

    // Automation
    Route::post('automations/{uid}/api/call', 'AutomationController@apiCall');

    // Sending server
    Route::resource('sending_servers', 'SendingServerController')->names([
        'index' => 'api.sending_servers.index',
        'create' => 'api.sending_servers.create',
        'store' => 'api.sending_servers.store',
        'show' => 'api.sending_servers.show',
        'edit' => 'api.sending_servers.edit',
        'update' => 'api.sending_servers.update',
        'destroy' => 'api.sending_servers.destroy',
    ]);

    // Customer
    Route::get('customers/by-email/{email}', 'CustomerController@findByEmail');
    Route::post('customers/{uid}/subscription/update', 'CustomerController@subscriptionUpdate');
    Route::post('customers/{uid}/change-plan/{plan_uid}', 'CustomerController@changePlan');
    Route::match(['get','post'], 'login-token', 'CustomerController@loginToken');
    Route::post('customers/{uid}/assign-plan/{plan_uid}', 'CustomerController@assignPlan');
    Route::patch('customers/{uid}/disable', 'CustomerController@disable');
    Route::patch('customers/{uid}/enable', 'CustomerController@enable');
    Route::resource('customers', 'CustomerController')->names([
        'index' => 'api.customers.index',
        'create' => 'api.customers.create',
        'store' => 'api.customers.store',
        'show' => 'api.customers.show',
        'edit' => 'api.customers.edit',
        'update' => 'api.customers.update',
        'destroy' => 'api.customers.destroy',
    ]);

    // Subscription
    Route::resource('subscriptions', 'SubscriptionController')->names([
        'index' => 'api.subscriptions.index',
        'create' => 'api.subscriptions.create',
        'store' => 'api.subscriptions.store',
        'show' => 'api.subscriptions.show',
        'edit' => 'api.subscriptions.edit',
        'update' => 'api.subscriptions.update',
        'destroy' => 'api.subscriptions.destroy',
    ]);

    // File
    Route::post('file/upload', 'FileController@upload');

    // File
    Route::post('automations/{uid}/execute', 'AutomationController@execute')->name('automation_execute');

    Route::post('notification/bounce', 'NotificationController@bounce');
    Route::post('notification/feedback', 'NotificationController@feedback');

    // User
    Route::get('user/info', 'UserController@info');

    // Dashboard
    Route::get('dashboard', 'DashboardController@index');

    // Automation
    Route::get('automations', 'AutomationController@index');

    // Plugin install from download URL (admin only; authorization enforced inside controller)
    Route::post('plugins/install', 'PluginController@install')->name('api.plugins.install');

    // Remote core upgrade — MUST be called as two separate HTTP requests
    // (step 2 needs a fresh PHP worker that loads the newly-replaced files).
    // See .support/HANDBOOK_DETAILS.md § Method API.
    Route::post('upgrade/run', 'UpgradeController@run')->name('api.upgrade.run');
    Route::post('upgrade/run-file', 'UpgradeController@runFile')->name('api.upgrade.run_file');
    Route::post('upgrade/finalize', 'UpgradeController@finalize')->name('api.upgrade.finalize');

    // License refresh (mirrors Admin → Settings → License → Refresh button)
    Route::post('license/refresh', 'LicenseController@refresh')->name('api.license.refresh');

    // `api.ai.obs.export` moved into the acelle/ai plugin's routes.php
    // (W4 of the AI-extraction plan).

});

Route::group(['namespace' => '\App\Http\Controllers\Api', 'prefix' => 'v1', 'middleware' => []], function () {
    // User
    Route::post('user/login', 'UserController@login');

});

// AI Task framework — moved into the acelle/ai plugin's routes.php
// (W4 of the AI-extraction plan). The `/api/v1/ai/*` route group + the
// `api.ai.*` named routes are now owned by `Acelle\Ai\ServiceProvider`.

// Hub AI passthrough — main-app endpoint used by downstream Acelle
// instances to forward AI calls through this instance's local Claude
// Code CLI binary. Hub is OWNED BY MAIN APP (not the plugin) because
// the engine, config, and observability story is operator-level — see
// `App\Http\Controllers\Api\AIHubController` + ENV `HUB_AI_CLAUDE_CLI_*`.
// Plugin must be installed for the `ClaudeCLIClient` class.
Route::group(['namespace' => '\App\Http\Controllers\Api', 'prefix' => 'v1', 'middleware' => ['auth:api']], function () {
    Route::post('hub-ai/handle', 'AIHubController@handle')->name('api.hub_ai.handle');
});

Route::group(['namespace' => '\App\Http\Controllers\Api\Public', 'prefix' => 'v1'], function () {
    Route::post('public/subscribers', 'SubscriberController@store');

    // Email Verification
    Route::get('email-verification/get-checkout-url', 'EmailVerificationController@getCheckoutUrl');
    Route::get('email-verification/get-subscription', 'EmailVerificationController@getSubscription');
    Route::post('email-verification/customer/find-create', 'EmailVerificationController@findOrCreateCustomer');
    Route::get('email-verification/feature-plan', 'EmailVerificationController@getFeaturePlan');
    Route::post('email-verification/subscribe', 'EmailVerificationController@subscribe');

});

// Athena EVS routes have been moved to the plugin: storage/app/plugins/athena/evs/routes.php