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

Vk Php Sdk Laravel Package

vkcom/vk-php-sdk

Official VK PHP SDK for building applications on the VK API. It provides OAuth authorization, a client for calling API methods, and helpers for responses and uploads, simplifying VK integration in PHP projects.

Deep Wiki
Context7

Getting Started

The SDK is a thin, schema-generated HTTP client — there is no Laravel service provider, facade, or config file. Everything starts from one class:

composer require vkcom/vk-php-sdk
use VK\Client\VkApiClient;

$vk = new VkApiClient('5.199'); // API version is a required constructor argument

The first useful call is almost always a token + users()->get() smoke test:

$users = $vk->users()->get($accessToken, [
    'user_ids' => [1, 6492],
    'fields'   => ['photo_200', 'city'],
]);

Things to know before you write anything:

  • VK\Client\VkApiClient is the entry point. Every service is a method on it (users(), wall(), photos(), messages(), groups(), friends(), orders(), etc.). Each service method takes the access token as the first argument, then a params array.
  • Authentication lives in VK\Client\OAuth\ — OAuth\Client returns an ImplicitFlow (JS / client-side) or AuthorizationCodeFlow (server-side redirect code exchange). The resulting AccessToken object exposes getAccessToken(), getUserId(), getExpiresIn().
  • Exceptions live in VK\Client\Exceptions\ — you will spend most of your debugging time distinguishing VkApiException (VK returned an error JSON) from VkClientException (network/transport).
  • Response shape is already unwrapped. The SDK decodes JSON and returns the response value directly as an array. You will not see ['response' => ...] when writing $vk->users()->get(...).

The fastest end-to-end flow in a fresh Laravel app: put a long-lived community (group) access token or service token in config/services.php, bind VkApiClient as a singleton in a provider, and start calling read-only methods like users()->get(), groups()->getById(), wall()->get() before touching OAuth.

Implementation Patterns

1. Bind the client as a singleton

Config:

// config/services.php
'vk' => [
    'version' => env('VK_API_VERSION', '5.199'),
    'token'   => env('VK_SERVICE_TOKEN'),
    'oauth'   => [
        'client_id'     => env('VK_CLIENT_ID'),
        'client_secret' => env('VK_CLIENT_SECRET'),
        'redirect'      => env('VK_REDIRECT_URI'),
    ],
],

Provider:

use VK\Client\VkApiClient;
use VK\Client\Enums\VkLanguage;

$this->app->singleton(VkApiClient::class, fn () => new VkApiClient(
    config('services.vk.version'),
    null, // default CurlRequest; see gotchas below
    VkLanguage::ENGLISH,
));

Inject VkApiClient $vk into controllers, jobs, and services. Never new VkApiClient() inside a controller — the version string and transport should be one decision, made once.

2. Wrap the SDK in a dedicated service class

The SDK returns plain arrays with inconsistent key casing (user_id, photo_200, first_name). Do not leak those into your domain:

final class VkUserDirectory
{
    public function __construct(private VkApiClient $vk) {}

    /** @return array<int, array{id:int,name:string,photo:?string}> */
    public function byIds(array $ids, string $token): array
    {
        $rows = $this->vk->users()->get($token, [
            'user_ids' => implode(',', $ids),
            'fields'   => ['photo_200'],
        ]);

        return array_map(fn ($u) => [
            'id'    => (int) $u['id'],
            'name'  => trim(($u['first_name'] ?? '') . ' ' . ($u['last_name'] ?? '')),
            'photo' => $u['photo_200'] ?? null,
        ], $rows);
    }
}

3. OAuth: use AuthorizationCodeFlow, not ImplicitFlow

For a Laravel backend, the flow is: redirect the user to VK, receive ?code=, then exchange server-side.

use VK\Client\OAuth\Client as OAuthClient;
use VK\Client\OAuth\Scope;

$oauth = new OAuthClient();
$flow  = $oauth->getAuthorizationCodeFlow();

// Step 1 — redirect
$scope = Scope::create()->withFriends()->withPhotos()->withOffline();
$url   = $flow->getAuthorizeUrl(
    config('services.vk.oauth.client_id'),
    config('services.vk.oauth.redirect'),
    $scope,
);

// Step 2 — callback
$token = $flow->getAccessToken(
    config('services.vk.oauth.client_id'),
    config('services.vk.oauth.client_secret'),
    config('services.vk.oauth.redirect'),
    $request->query('code'),
);

$token->getAccessToken(); // persist encrypted
$token->getUserId();
$token->getExpiresIn();   // store expiry; the SDK will not refresh for you

Request offline scope if you need long-lived tokens; otherwise schedule a refresh job before expires_in elapses.

4. Callback API (webhooks) as a controller

use VK\Client\CallbackApi\CallbackApiHandler;

final class VkCallbackHandler extends CallbackApiHandler
{
    protected function handleMessageNew(array $event): void
    {
        // $event['object'] and $event['group_id'] are your payload
        ProcessVkMessage::dispatch($event['object']);
    }

    protected function handleWallPostNew(array $event): void { /* ... */ }
}

The base handler verifies the secret, answers the confirmation event automatically, and dispatches to handle{EventName} methods. Register a single POST route, read php://input, and call ->handle().

5. LongPoll for bots, Streaming for mass data

  • LongPoll (VK\Client\LongPoll\LongPoll, events parsed via VK\Client\Events\Events) is a better fit than webhooks when you are behind a firewall or need sub-second event delivery. Get server, key, ts from groups->getLongPollServer(), poll, persist ts.
  • StreamingClient (VK\Client\StreamingClient) taps firehose rules (streaming()->getRules(), addRule()) — use it for analytics, not for interactive replies.

6. Error handling and retries

use VK\Client\Exceptions\VkApiException;
use VK\Client\Exceptions\ApiErrorCodes;

try {
    return $vk->wall()->post($token, $params);
} catch (VkApiException $e) {
    if (in_array($e->getErrorCode(), [
        ApiErrorCodes::TOO_MANY_REQUESTS_PER_SECOND, // 6
        ApiErrorCodes::FLOOD_CONTROL,                // 9
    ], true)) {
        throw new RateLimitedVkException($e->getErrorMessage(), previous: $e);
    }
    throw $e;
}

Put this in a single base VkJob/middleware rather than repeating it in every call. For batch-heavy work use the universal execute method (up to 25 calls per request) and queue it — this is the single biggest throughput win available.

Gotchas and Tips

  • The API version is not optional and it changes response shapes. Pin it in config, not in code. Methods added in 5.199 will silently return error code 3 ("Unknown method passed") if you send 5.131.
  • ImplicitFlow is for browser-side token acquisition only. If you try to exchange a code server-side with ImplicitFlow you will get an invalid-request error. Use AuthorizationCodeFlow.
  • The SDK does not refresh tokens. Persist expires_in alongside the token and refresh proactively. A 401 (error code 5) from VK almost always means "expired token", not "wrong scope".
  • Captcha (error code 14) is unsolvable inside the SDK. You must redirect the user to redirect_uri?captcha_sid=...&captcha_key=.... Detect it in your error mapper and surface a 302, not a 500.
  • ApiRequest is your seam for testing and logging. The interface is small (send(string $url, array $params): string). Swap in a fake that returns canned JSON to unit-test your service layer without hitting VK; decorate it to log every outbound URL and body.
  • CurlRequest requires ext-curl. If your host lacks it, use VK\Client\Request\StreamRequest (based on file_get_contents). This is a one-line constructor change, but it is easy to miss because the failure surfaces as a generic VkClientException.
  • Rate limits are stricter than you expect: ~3 req/s for user tokens, ~20 req/s for service tokens, ~3 req/s per community. Wrap the client in Illuminate\Cache\RateLimiter or a Redis token bucket, especially before you scale queue workers.
  • Some methods return [] and some return objects. users()->get() with a single valid id returns a 1-element list; with an invalid id it returns an empty list, not a 404. Normalize upstream.
  • execute swallows errors into per-call payloads. A failed inner call comes back as ['response' => [...], 'execute_errors' => [...]]; the SDK treats it as success. Inspect execute_errors explicitly.
  • Callback API confirmation must be answered verbatim. The base handler does this, but if you write a custom router you must echo the raw confirmation string, or VK will mark the webhook as failing.
  • Event handler method names are camelized from the event type. message_new → handleMessageNew, wall_wall_post_new → handleWallPostNew. Typos are silent — your handler simply never fires. Log every incoming event during integration.
  • Callback and LongPoll group_id/ts are stateful. Store ts and key in cache/DB between polls; if you lose them, events are lost, not replayed.
  • Maintenance risk: the library's release cadence is slow and it has no PSR-18/PSR-7 alignment. Budget for occasional manual patches (PHP version bumps, transport quirks). Because the surface is small (VkApiClient + ApiRequest), wrapping it behind your own interface lets you swap in a hand-rolled client later without touching call sites.
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.
mydnic/volet-feature-board-filament-plugin
wmde/email-address
refinery29/test-util
dees040/laravel-api-responses
teamzac/geocoder
ideatica/config-writer
keaton-php/pipe-dream
jacksonwebservices/laravel-user-suite
maksimru/conditional-laravel-debugbar
gismatul/nova-support-chat
gismatul/laravel-support-chat
networkrailbusinesssystems/oracle-api
alphabalex/messaging-made-easy
rawphp/warp
shootkiran/merobug
narakode/fineauth
numencode/wn-syncops-plugin
ibnnajjaar/mib-global-pay
refinery29/php-cs-fixer-config
parsnick/steak