Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Laravel Zoom Laravel Package

macsidigital/laravel-zoom

A Laravel wrapper for the Zoom API that lets you manage meetings, users, webinars, and recordings from your PHP app. It provides a clean, expressive interface for common Zoom operations, making it easy to integrate video conferencing into Laravel projects.

View on GitHub
Deep Wiki
Context7

Getting Started

  1. Install the package:

    composer require macsidigital/laravel-zoom
    
  2. Publish the config and set credentials:

    php artisan vendor:publish --provider="MacsiDigital\Zoom\Providers\ZoomServiceProvider"
    php artisan config:clear
    

    Typical .env entries are:

    ZOOM_API_KEY=...
    ZOOM_API_SECRET=...
    

    Check config/zoom.php first. On Laravel versions without package auto-discovery, register MacsiDigital\Zoom\Providers\ZoomServiceProvider and the Zoom facade alias manually.

  3. Confirm auth model before building. This package was commonly used with Zoom JWT API key/secret credentials, and Zoom deprecated JWT app creation in 2023. For a new integration, verify the package version supports Server-to-Server OAuth or OAuth token refresh; otherwise treat it as a legacy/internal-tool dependency or fork it.

  4. First use case: schedule a meeting for a host and persist the Zoom response locally.

    use MacsiDigital\Zoom\Facades\Zoom;
    
    $host = Zoom::user()->find('me'); // or a specific Zoom user ID
    
    $meeting = $host->meetings()->create([
        'topic' => 'Discovery call',
        'type' => 2, // scheduled meeting
        'start_time' => $start->toIso8601String(),
        'duration' => 30,
        'timezone' => config('app.timezone'),
        'settings' => [
            'waiting_room' => true,
            'join_before_host' => false,
            'auto_recording' => 'none',
        ],
    ]);
    
    // Store these, not just the Zoom object
    $zoomMeetingId = $meeting->id;
    $joinUrl = $meeting->join_url;
    $startUrl = $meeting->start_url; // host-only; never send to attendees
    

Look first at the README examples, config/zoom.php, the Zoom facade, and the model classes for User, Meeting, Webinar, and Recording. The package is a thin API wrapper, not an Eloquent replacement, so expect Zoom-shaped payloads rather than Laravel-native models.

Implementation Patterns

  • Wrap the facade in your own service. Keep Zoom::... calls in one or two application services so auth changes, package replacement, and testing are contained.

    class ZoomMeetingService
    {
        public function schedule(User $localUser, array $data): ZoomMeetingRecord
        {
            $host = Zoom::user()->find($localUser->zoom_user_id);
    
            $meeting = $host->meetings()->create([
                'topic' => $data['topic'],
                'type' => 2,
                'start_time' => $data['starts_at']->toIso8601String(),
                'duration' => $data['duration'],
                'timezone' => $data['timezone'] ?? config('app.timezone'),
            ]);
    
            return ZoomMeetingRecord::create([
                'user_id' => $localUser->id,
                'zoom_id' => (string) $meeting->id,
                'topic' => $meeting->topic,
                'join_url' => $meeting->join_url,
                'start_url' => $meeting->start_url,
                'starts_at' => $data['starts_at'],
                'payload' => $meeting->toArray(),
            ]);
        }
    }
    
  • Persist a local mapping table. Store zoom_id as a string, plus join_url, start_url, topic, start_time, timezone, status, and raw payload JSON. Do not rely on reconstructing state from Zoom alone; you will need local joins, auditability, and webhook reconciliation.

  • Use an “API call plus local state” workflow. Create a local pending record, call Zoom, then update with the returned ID and URLs. If the API call fails, keep the record failed so it can be retried rather than losing the user’s intent.

  • Treat scheduling, rescheduling, and cancellation as separate operations.

    $meeting = Zoom::meeting()->find($zoomMeetingId);
    
    $meeting->update([
        'topic' => 'Rescheduled discovery call',
        'start_time' => $newStart->toIso8601String(),
        'duration' => 45,
    ]);
    
    // Cancels the meeting in Zoom; it is not a hard delete in your local DB.
    $meeting->delete();
    

    For recurring meetings, track occurrence IDs and update/cancel the occurrence explicitly.

  • Sync users deliberately. Zoom::user()->all() is useful for admin screens and provisioning, but plan for pagination and rate limits. Use Zoom::user()->find('me') for the authenticated OAuth user, and explicit Zoom user IDs for host selection.

  • Use relationships for nested resources. Meeting registrants, webinar registrants, and recordings are usually reached through the user/meeting/webinar model:

    $recordings = Zoom::user()->find($zoomUserId)->recordings()->all();
    
  • Prefer webhooks for lifecycle changes. Do not poll Zoom for meeting started/ended or recording completed events. Handle Zoom webhooks in a controller, verify the signature, queue a job, then update your local meeting/recording records.

  • Queue outbound Zoom calls. Meeting creation from a web request is usually acceptable, but bulk user sync, recording import, and webinar registrant sync should run in jobs with retries and backoff.

  • Store secrets and URLs correctly. start_url is host-only and should be permission-gated. join_url is attendee-facing. Treat both as sensitive because they grant meeting access.

Gotchas and Tips

  • Maintenance and version risk are the biggest concerns. The last release was September 2023, the package is a thin wrapper, and Zoom’s auth model has changed. Check Composer constraints against your Laravel/PHP version before committing. For production, pin the version and be prepared to fork or replace it.

  • JWT is the trap. If the installed version expects ZOOM_API_KEY/ZOOM_API_SECRET JWT credentials, do not assume it works with a new Zoom app. Server-to-Server OAuth requires account-level setup and scopes; user-level OAuth requires redirect handling and token refresh. Confirm what the package actually sends before building workflows around it.

  • Scopes fail late. A missing Zoom scope often appears only when calling a specific endpoint. Verify meeting:write, user:read, recording:read, webinar:write, and registrant scopes for the endpoints you use.

  • Rate limits and 429s need handling. Wrap calls with retry/backoff and respect Retry-After. Batch jobs should be chunked and queued, not looped synchronously over hundreds of users or recordings.

  • Pagination is easy to miss. A call that looks like it returns “all” meetings or users may return only the first page. Inspect the package methods and Zoom response for next_page_token; implement paging explicitly if the wrapper does not.

  • Meeting IDs are large. Store Zoom meeting IDs as strings to avoid JavaScript numeric precision issues and to preserve leading behavior across systems.

  • Time zones and ISO 8601 matter. Always send start_time in ISO 8601 and set timezone explicitly. Test DST boundaries and recurring meetings; “same local time” is not the same as “same UTC time.”

  • Update payloads can be partial but fragile. Zoom update endpoints often accept partial fields, but the wrapper may hydrate models in ways that make nulls or omitted fields ambiguous. Log the outgoing payload when debugging unexpected changes.

  • delete() usually means cancel. A deleted meeting may still exist in reporting or recordings. Keep local status fields (scheduled, cancelled, ended) instead of deleting local rows.

  • Webhook verification is your responsibility. Verify x-zm-signature using the raw request body and x-zm-request-timestamp, and handle Zoom’s endpoint.url_validation challenge. Do not rely on the package for webhook security.

  • Debug with raw payloads. When a property is missing, call toArray() or log the underlying response. The package’s dynamic model properties are convenient but can hide API shape changes.

  • Config caching causes confusing auth failures. After changing .env or config/zoom.php, run php artisan config:clear. In production, rebuild config cache intentionally.

  • Testing should not hit Zoom. Mock your own ZoomMeetingService in feature tests. If you test the package directly, use HTTP fakes or a fake Zoom client behind your wrapper; do not let CI create real meetings.

  • Extension point: your service layer, not the package. Because the package is small and lightly maintained, the safest extension point is a local adapter interface around it. That lets you swap in direct Guzzle calls, a newer Zoom SDK, or a maintained fork without rewriting controllers and jobs.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
3mdikram/worldmoneywords
snowsoft/config
itmosoft/laravel-subscriptions
larva/laravel-ai-qwen
diephp/sequences
users-au/socialite-provider
twidpay/twid-logger
mrnewport/laravel-plaid
mrnewport/laravel-repo
mrnewport/laravel-docsign
mrnewport/laravel-stow
mrnewport/laravel-flow
mrnewport/laravel-priceable
mrnewport/laravel-nestedterms
fredmeng/laravel-apidoc-generator
itstructure/laravel-multilingual-tools
pdustdar/elasticsearch
markupai/php-sdk
rlacerda83/lumem-microservice-shipment
uni-method/symfony-lib