yandex-money/yandex-money-sdk-php
PHP SDK for Yandex.Money (YooMoney) API integration. Simplifies OAuth authorization, wallet operations, and payment processing, letting developers add Yandex.Money payments to PHP applications with minimal setup. Includes convenient client classes and request handling for quick, reliable integration...
Minimal setup in a Laravel app:
composer require yandex-money/yandex-money-sdk-php. The package is under the YandexMoney\ namespace and autoloads via PSR-4; there is no service provider, facade, or config file shipped with it.config/services.php:
'yoomoney' => [
'client_id' => env('YOOMONEY_CLIENT_ID'),
'client_secret' => env('YOOMONEY_CLIENT_SECRET'),
'redirect_uri' => env('YOOMONEY_REDIRECT_URI'),
],
src/YandexMoney/API.php (wallet endpoints), src/YandexMoney/Client.php (OAuth: getAuthUrl, receiveToken, revokeToken), and src/YandexMoney/ExternalPayment.php (card-based payments without a Yandex wallet). Those three classes cover ~90% of daily use.code for an access token:
use YandexMoney\Client;
$client = new Client(
config('services.yoomoney.client_id'),
config('services.yoomoney.client_secret')
);
return redirect($client->getAuthUrl(
config('services.yoomoney.redirect_uri'),
['account-info', 'operation-history', 'payment-p2p']
));
new YandexMoney\API($token) for wallet operations like accountInfo().Token lifecycle. Exchange the code in your callback route, then persist the token:
$response = $client->receiveToken(request('code'), config('services.yoomoney.redirect_uri'));
// $response->access_token, ->refresh_token, ->expires_in, ->token_type
$user->update(['yoomoney_token' => encrypt($response->access_token)]);
Keep refresh_token too — Yandex rotates tokens, and rebuilding from scratch loses the user's consent scope.
Bind an API client per request, not globally. A small service class keeps controllers clean and makes the SDK swappable:
class YooMoneyApi
{
public function for(User $user): \YandexMoney\API
{
return new \YandexMoney\API(decrypt($user->yoomoney_token));
}
}
Resolve it from the container via AppServiceProvider (singleton is fine because the token is injected per call).
External payments workflow (card, no wallet). Use ExternalPayment for two-step flows: request() to create a payment and get a request_id, redirect the user to the returned redirect_url, then process() with the request_id when the user returns. Persist request_id in your orders table so a queue job can reconcile status later.
Payment status is asynchronous. Never trust the browser return alone. Schedule a CheckYooMoneyPayment job (queued, with backoff()) that calls operationHistory()/operationDetails() and updates your order. This is the pattern most production integrations end up needing.
Wallet-to-wallet (P2P). requestPayment() returns a request_id; the recipient must accept it via incomingTransferAccept(), otherwise it auto-reverts. Model this as a state machine on your order, not a boolean.
Webhooks vs polling. The SDK does not ship a webhook parser. Yandex POSTs HTTP notifications to your callback URL with operation_id, sha1_hash, etc. Verify the sha1_hash manually (concatenate the notify fields + your secret) before trusting it, then call operationDetails() to confirm — treat the webhook purely as a wake-up signal.
Testing. Wrap the SDK behind an interface and bind a fake in TestCase. Mockery can't mock the concrete SDK classes usefully because the constructors do real setup; a thin port/interface is the pragmatic route.
json_decode($api->accountInfo(), true) on every call, or wrap it once in your service class. This trips up everyone the first time.{"error": "invalid_token", "error_description": ...}. Check isset($result['error']) before assuming success — the SDK won't throw for auth failures.invalid_client on token exchange. Keep it in .env and reuse the same value in both getAuthUrl() and receiveToken().payment-p2p, the API returns insufficient_scope and there's no way to escalate without a new OAuth round-trip. Decide scopes upfront.API and override sendRequest(), or (better) bypass the SDK and use Http::withToken(...) directly — the API is plain HTTPS+JSON and the SDK adds little.revokeToken() and set yoomoney_token to null. Otherwise revoked-but-stored tokens silently fail with invalid_grant later and look like data corruption.Client/API at the test base URL (the SDK exposes endpoint options in some constructors) and use the test wallet before touching real money. Do not debug with real balances.laravel.log and any exception handlers; add the token to config/logging.php's redaction list.error_reporting(E_ALL & ~E_DEPRECATED) in tests, or fork into a namespaced copy.yandex-money/yandex-money-sdk-php but the class prefix is YandexMoney\. A surprising number of developers look for a YandexMoneySdk namespace and give up.How can I help you explore Laravel packages today?