laravel-cloud-client maintained by foundry-co
Laravel Cloud Client
A fluent Laravel client for the Laravel Cloud API, built on Laravel's HTTP client.
Installation
composer require foundry-co/laravel-cloud-client
Publish the config:
php artisan vendor:publish --tag=cloud-config
Set your API token in .env:
LARAVEL_CLOUD_TOKEN=your-token-here
Usage
Use the Cloud facade or resolve CloudClient from the container.
use FoundryCo\LaravelCloudClient\Facades\Cloud;
$application = Cloud::applications()->find($applicationId);
$environment = $application->environments()->create(name: 'production', branch: 'main');
$environment->update(phpVersion: '8.3', buildCommand: 'npm run build');
$environment->addVariables(['APP_DEBUG' => 'false']);
$environment->domains()->create('example.com', wwwRedirect: 'www');
$environment->deploy();
Every record is an immutable model that knows its client. Calling update() or refresh() returns a fresh instance, and children are reached through relationship methods such as $environment->domains().
Conventions
- Attributes are passed as named arguments in camelCase (
wwwRedirect: 'www'). They are sent as snake_case, andnullvalues are omitted. - Required attributes can be passed positionally:
create('example.com'),create('production', 'main'). - Filters are named arguments on
list():list(status: 'running')sendsfilter[status]=running. - Pagination is automatic.
list()returns aCollectionof every page. - Scoping. Child resources take their parent as an optional argument:
Cloud::domains($environmentId). The same resource is available from the parent model:$environment->domains(). - Errors throw
AuthenticationException(401),NotFoundException(404),ValidationException(422, with->errors) orCloudApiException.
Applications
Cloud::applications()->list();
Cloud::applications()->list(name: 'my-app', region: 'us-east-1');
Cloud::applications()->find($applicationId);
Cloud::applications()->create(repository: 'my-org/my-repo', name: 'My App', region: 'us-east-1');
$application->update(name: 'New Name');
$application->uploadAvatar('/path/to/avatar.png');
$application->deleteAvatar();
$application->environments();
$application->delete();
Environments
Cloud::environments($applicationId)->list(status: 'running');
Cloud::environments()->find($environmentId);
$environment->update(phpVersion: '8.3', usesOctane: true);
$environment->start(redeploy: true);
$environment->stop();
$environment->purgeEdgeCache(path: '/assets');
$environment->metrics(period: '24h');
$environment->logs(from: '2024-01-01T00:00:00Z', to: '2024-01-02T00:00:00Z', query: 'error', caseSensitive: true);
$environment->run('php artisan about');
$environment->deploy();
$environment->delete();
$environment->addVariables(['APP_DEBUG' => 'false']);
$environment->replaceVariables(['APP_ENV' => 'production']);
$environment->deleteVariables(['OLD_KEY']);
$environment->updateVanityDomain('my-app');
$environment->attachSecrets([$secretId]);
$environment->detachSecret($secretId);
$environment->attachResend(fromAddress: 'hi@example.com', fromName: 'Example');
$environment->updateResend(fromAddress: 'hello@example.com', fromName: 'Example');
$environment->resendKeys();
$environment->detachResend();
start() returns the Deployment. The other actions return the updated Environment. Variables may be given as ['KEY' => 'value'] or as the API's [['key' => 'KEY', 'value' => 'value']].
Relationships: domains(), instances(), deployments(), commands().
Deployments
$environment->deployments()->list(status: 'deployment.succeeded');
Cloud::deployments()->find($deploymentId);
$deployment = $environment->deploy();
$deployment->status;
$deployment->succeeded();
$deployment->failed();
$deployment->isInProgress();
$deployment->logs();
Domains
$environment->domains()->list();
$domain = $environment->domains()->create('example.com', wildcardEnabled: true);
$domain->update(verificationMethod: 'real_time');
$domain->verify();
$domain->isPrimary();
$domain->delete();
Instances
$environment->instances()->create(
name: 'web',
type: InstanceType::Service,
size: 'flex-1gb',
scalingType: InstanceScalingType::Auto,
minReplicas: 1,
maxReplicas: 3,
);
Cloud::instances()->sizes();
$instance->update(maxReplicas: 5);
$instance->delete();
$instance->backgroundProcesses();
$instance->scheduledCommands();
$instance->setDefault();
$instance->pause();
$instance->resume();
$instance->purge();
$instance->failedJobs();
$instance->retryFailedJob($jobId);
$instance->deleteFailedJob($jobId);
$instance->deleteFailedJobs(jobIds: [$jobId], failedBefore: '2024-01-01');
Scheduled Commands
$instance->scheduledCommands()->list();
$instance->scheduledCommands()->create('php artisan reports:send', '0 8 * * *', name: 'Daily report');
$command->update(schedule: '0 9 * * *');
$command->delete();
Background Processes
$instance->backgroundProcesses()->list();
$instance->backgroundProcesses()->create(type: 'worker', command: 'php artisan queue:work', processes: 2);
$process->update(processes: 4);
$process->delete();
Commands
$environment->commands()->list(status: 'command.success');
$command = $environment->run('php artisan migrate --force');
$command->refresh();
Database Clusters
Cloud::databaseClusters()->list(type: 'neon_serverless_postgres');
Cloud::databaseClusters()->types();
Cloud::databaseClusters()->presets(type: 'neon_serverless_postgres', region: 'us-east-1');
Cloud::databaseClusters()->create(
type: 'neon_serverless_postgres',
name: 'my-db',
region: 'us-east-1',
version: $version,
config: ['cu_min' => 0.25, 'cu_max' => 1],
);
$cluster->update(config: ['cu_max' => 2]);
$cluster->metrics(period: '24h');
$cluster->databases();
$cluster->snapshots();
$cluster->snapshot('before-migration');
$cluster->restore(name: 'my-db-restored', snapshotId: $snapshotId);
$cluster->delete();
Databases
Schemas within a cluster.
$cluster->databases()->list();
$cluster->databases()->create('analytics');
$database->delete();
Database Snapshots
$cluster->snapshots()->list();
$snapshot = $cluster->snapshot('before-migration');
$snapshot->restore('my-db-restored');
$snapshot->delete();
Caches
Cloud::caches()->list();
Cloud::caches()->create(type: 'laravel_valkey', name: 'cache', region: 'us-east-1', size: 'valkey-flex-250mb');
Cloud::caches()->types();
$cache->update(size: 'valkey-flex-1gb');
$cache->metrics(period: '24h');
$cache->delete();
Object Storage Buckets
Cloud::objectStorageBuckets()->list(visibility: 'public');
Cloud::objectStorageBuckets()->create(name: 'assets', keyName: 'uploads', visibility: 'public');
$bucket->update(visibility: 'private', allowedOrigins: ['https://example.com']);
$bucket->keys();
$bucket->delete();
Bucket Keys
$bucket->keys()->list();
$bucket->keys()->create('uploads', permission: 'read_only');
$key->update(name: 'renamed');
$key->delete();
WebSocket Clusters
Cloud::websocketClusters()->list();
Cloud::websocketClusters()->types();
Cloud::websocketClusters()->create(name: 'realtime', region: 'us-east-1', maxConnections: 500);
$cluster->update(maxConnections: 2000);
$cluster->metrics(period: '24h');
$cluster->applications();
$cluster->delete();
WebSocket Applications
$cluster->applications()->list();
$cluster->applications()->create('chat', allowedOrigins: ['https://example.com'], pingInterval: 30);
$application->update(activityTimeout: 60);
$application->metrics(period: '24h');
$application->delete();
Dedicated Clusters
Cloud::dedicatedClusters()->list(region: 'us-east-1');
Edge Networks
Cloud::edgeNetworks()->list(status: 'available');
Resend Domains
Cloud::resendDomains()->list(status: 'verified');
Secrets
Cloud::secrets()->list(key: 'STRIPE_KEY');
Cloud::secrets()->publicKey();
Cloud::secrets()->create(keyPairId: $keyPairId, key: 'STRIPE_KEY', value: $encryptedValue, notes: 'Live key');
$secret->update(key: 'STRIPE_KEY', value: $encryptedValue);
$secret->delete();
Secret values are submitted as the API expects them, encrypted against the organization's public key.
Meta
Cloud::meta()->organization();
Cloud::meta()->regions();
Usage
Cloud::usage()->get();
Cloud::usage()->get(period: 1, environment: $environmentId);
Testing
The client uses Laravel's HTTP client, so Http::fake() works as usual:
use Illuminate\Support\Facades\Http;
Http::fake([
'cloud.laravel.com/api/applications*' => Http::response([
'data' => [['id' => 'app-1', 'type' => 'applications', 'attributes' => ['name' => 'My App']]],
'links' => ['next' => null],
]),
]);
Cloud::applications()->list();
Http::assertSent(fn ($request) => $request->url() === 'https://cloud.laravel.com/api/applications?page=1');
License
MIT