artempuzik / musewallet-sdk-laravel
MuseWallet SDK for Laravel - Integration with MusePay Card API v1
Installs: 1
Dependents: 0
Suggesters: 0
Security: 0
Stars: 0
Watchers: 0
Forks: 0
Open Issues: 0
pkg:composer/artempuzik/musewallet-sdk-laravel
Requires
- php: ^8.1
 - ext-json: *
 - ext-openssl: *
 - illuminate/cache: ^10.0|^11.0
 - illuminate/events: ^10.0|^11.0
 - illuminate/http: ^10.0|^11.0
 - illuminate/log: ^10.0|^11.0
 - illuminate/support: ^10.0|^11.0
 
Requires (Dev)
- mockery/mockery: ^1.6
 - orchestra/testbench: ^8.0|^9.0
 - phpstan/phpstan: ^1.10
 - phpunit/phpunit: ^10.0
 
README
A comprehensive Laravel SDK for integrating with MusePay Card API (MuseWallet). This package provides a clean, event-driven interface for managing virtual and physical cards, KYC verification, transactions, and webhooks. Includes optional database integration for storing card data locally with automatic synchronization.
API Version: v1 SDK Version: 1.1.0 Compatible with: MusePay Card API v1 Documentation: https://docs-card.musepay.io
Features
- 🚀 Easy integration with MusePay Card API v1
 - 🎯 Full support for all MusePay endpoints
 - 🔐 Built-in RSA signature generation and webhook verification
 - 🎪 Event-driven webhook handling
 - 📦 Comprehensive error codes with descriptions
 - ✅ Extensive test coverage
 - 📝 Type hints and PHPDoc annotations
 - 🎁 Typed responses (DTO) for all API methods
 - 🎮 Ready-to-use controller with validation
 - 🔄 Automatic retry logic with exponential backoff
 - 💾 Optional response caching
 - 📊 Detailed logging support
 - 🗄️ Optional database integration with automatic data synchronization
 - 🔒 Automatic encryption of sensitive card data
 - 📈 Card history tracking with timestamps
 
Requirements
- PHP 8.1 or higher
 - Laravel 10.0 or 11.0
 - OpenSSL PHP extension
 
Installation
Option 1: Install from Packagist (Recommended when published)
composer require artempuzik/musewallet-sdk-laravel
Option 2: Install from GitHub (Before Packagist publication)
If the package is not yet published on Packagist, add the GitHub repository to your composer.json:
"repositories": [ { "type": "vcs", "url": "https://github.com/artempuzik/musewallet-sdk-laravel.git" } ],
Then install:
composer require artempuzik/musewallet-sdk-laravel:^1.0
That's it! The package is ready to use. Laravel will automatically discover and register the service provider.
Configuration
Step 1: Environment Variables (Required)
Add the following environment variables to your .env file:
MUSEWALLET_API_URL=https://api.test.musepay.io MUSEWALLET_PARTNER_ID=your_partner_id MUSEWALLET_PRIVATE_KEY="-----BEGIN RSA PRIVATE KEY----- Your private key here -----END RSA PRIVATE KEY-----" # Card Products (obtain from MusePay) MUSEWALLET_BASIC_CARD_PRODUCT_ID=prod_basic_card_id MUSEWALLET_PREMIUM_CARD_PRODUCT_ID=prod_premium_card_id # Webhook Configuration MUSEWALLET_WEBHOOK_SECRET=your_webhook_secret # Optional Settings MUSEWALLET_API_TIMEOUT=30 MUSEWALLET_RETRY_ATTEMPTS=3 MUSEWALLET_CACHE_ENABLED=true MUSEWALLET_CACHE_TTL=300 MUSEWALLET_LOGGING_ENABLED=true MUSEWALLET_EVENTS_ENABLED=true # Database Configuration (Optional) MUSEWALLET_USER_MODEL=App\Models\User MUSEWALLET_ENCRYPT_FIELDS=true
Step 2: Publish Configuration (Optional)
If you need to customize advanced settings (timeouts, cache, logging, card products), publish the configuration file:
php artisan vendor:publish --provider="MuseWallet\SDK\MuseWalletServiceProvider" --tag=musewallet-config
This will create config/musewallet.php where you can override default settings.
Note: Publishing the config file is optional. The package works with environment variables alone. Only publish if you need to customize advanced settings or manage multiple card products.
Step 3: Publish and Run Migrations (Optional)
If you want to store card information in your database, publish and run the migrations:
php artisan vendor:publish --tag=musewallet-migrations php artisan migrate
This will create the muse_wallet_cards table for storing card data locally.
Note: Database integration is optional. The SDK can work without database storage, but storing card data locally provides better performance and enables advanced features like card history tracking.
Basic Usage
Using the Facade (with typed responses)
use MuseWallet\SDK\Facades\MuseWallet; // Get partner balance - returns PartnerBalanceResponse $balance = MuseWallet::getPartnerBalance('USDT'); echo "Available: " . $balance->getAvailableBalanceFloat(); // Type-safe! echo "Currency: " . $balance->currency; echo "Freeze: " . $balance->freezeBalance; // Create card holder - returns CardHolderResponse $holder = MuseWallet::createCardHolder([ 'user_xid' => 'unique_user_id', 'email' => 'user@example.com', 'individual' => [ 'first_name' => 'John', 'last_name' => 'Doe', 'birthday' => '1990-01-01' ] ]); // Typed properties with IDE autocomplete $userId = $holder->getUserId(); // string|null $kycStatus = $holder->getKycStatus(); // string|null $email = $holder->email; // string|null // Apply for a card - returns CardApplicationResponse $application = MuseWallet::applyCard([ 'user_id' => $holder->userId, // Use typed property 'request_id' => \Illuminate\Support\Str::uuid(), 'card_product_id' => 'prod_basic_card_id', 'card_level' => '1', 'phone_number' => '1234567890', 'phone_area_code' => '1' ]); // Check application status if ($application->isSuccessful()) { $applyId = $application->getApplyId(); $status = $application->getStatus(); }
Using Dependency Injection (with typed responses)
use MuseWallet\SDK\Services\MuseWalletService; use MuseWallet\SDK\DataTransferObjects\CardApplicationResponse; class CardController extends Controller { public function __construct( private MuseWalletService $museWallet ) {} public function createCard(Request $request): JsonResponse { // Returns typed CardApplicationResponse $application = $this->museWallet->applyCard($request->validated()); // IDE autocomplete and type safety return response()->json([ 'success' => $application->isSuccessful(), 'apply_id' => $application->getApplyId(), 'status' => $application->getStatus(), 'card_id' => $application->getCardId(), ]); } }
Available Methods
Balance Operations
// Get partner balance $balance = MuseWallet::getPartnerBalance('USDT');
Card Holder Management
// Create card holder $holder = MuseWallet::createCardHolder([ 'user_xid' => 'unique_user_id', 'email' => 'user@example.com', 'individual' => [ 'first_name' => 'John', 'last_name' => 'Doe', 'birthday' => '1990-01-01' ], 'address' => [ 'country' => 'US', 'state' => 'CA', 'city' => 'Los Angeles', 'postal_code' => '90001', 'address_line1' => '123 Main St' ] ]);
KYC Management
// Upload KYC documents $kyc = MuseWallet::uploadKyc([ 'user_xid' => 'unique_user_id', 'individual' => [...], 'document' => [ 'type' => '1', // 1=Passport, 2=ID Card 'number' => 'P123456789', 'front_image' => 'base64_encoded_image', 'back_image' => 'base64_encoded_image' ] ]); // Generate KYC link $kycLink = MuseWallet::generateKycLink('unique_user_id');
Card Operations
// Apply for card $application = MuseWallet::applyCard([...]); // Query application result $result = MuseWallet::queryApplyResult($requestId, $userId); // Get card information $card = MuseWallet::getCard($cardId, $userId); // Activate card $activated = MuseWallet::activateCard([ 'user_id' => $userId, 'card_id' => $cardId ]); // Top up card $topup = MuseWallet::topUpCard([ 'request_id' => \Illuminate\Support\Str::uuid(), 'card_id' => $cardId, 'user_id' => $userId, 'amount' => '100.00', 'currency' => 'USDT' ]);
Database Operations (Optional)
If you've published and run the migrations, you can use database methods:
use MuseWallet\SDK\Services\MuseWalletService; $museWallet = app(MuseWalletService::class); // Create or update card holder in database $card = $museWallet->createOrUpdateCardHolder($userId, $cardHolderResponse); // Create or update card application in database $card = $museWallet->createOrUpdateCardApplication($userId, $applicationResponse); // Update card information $card = $museWallet->updateCardInfo($cardInfoResponse); // Get user's cards from database $cards = $museWallet->getUserCards($userId); // Get user's active cards $activeCards = $museWallet->getUserActiveCards($userId); // Get card by card ID $card = $museWallet->getCardById($cardId);
Automatic Database Updates:
The following API methods automatically save data to the database:
applyCard()- saves card application dataqueryApplyResult()- updates application statusgetCard()- updates card informationactivateCard()- updates card status after activation
Webhook Handling
The SDK uses a dedicated WebhookService to handle all webhook processing. You can use it through MuseWalletService (recommended) or directly for more control.
Setup Webhook Route
In your routes/api.php:
use MuseWallet\SDK\Services\MuseWalletService; Route::post('/webhooks/musewallet', function (Request $request, MuseWalletService $museWallet) { $payload = $request->all(); $signature = $request->header('X-Webhook-Signature', ''); try { // Verify signature if (!$museWallet->verifyWebhookSignature($payload, $signature)) { return response()->json(['error' => 'Invalid signature'], 401); } // Process webhook $result = $museWallet->processWebhook($payload); return response()->json($result); } catch (\Exception $e) { return response()->json(['error' => $e->getMessage()], 400); } });
Direct WebhookService Usage
For advanced use cases, you can use WebhookService directly:
use MuseWallet\SDK\Services\{MuseWalletService, WebhookService}; $webhookService = new WebhookService($transactionRepository); $webhookService->setMuseWalletService($museWalletService); // Verify signature if (!$webhookService->verifyWebhookSignature($payload, $signature)) { throw new Exception('Invalid webhook signature'); } // Process webhook $result = $webhookService->processWebhook($payload);
Listening to Webhook Events
The SDK automatically dispatches events for all webhook types. You can listen to these events in your application:
use MuseWallet\SDK\Events\{ CardCreatedEvent, CardActivatedEvent, TransactionCompletedEvent, TopUpCompletedEvent, KycApprovedEvent, ApplicationApprovedEvent }; // In your EventServiceProvider protected $listen = [ CardCreatedEvent::class => [ SendCardCreatedNotification::class, ], TransactionCompletedEvent::class => [ UpdateTransactionHistory::class, SendTransactionReceipt::class, ], TopUpCompletedEvent::class => [ UpdateCardBalance::class, ], ];
Supported Webhook Types
The SDK automatically handles these MusePay webhook types:
| Webhook Type | Description | Event Dispatched | Database Updated | 
|---|---|---|---|
APPLY_AUDIT | 
Card application approved/rejected | ApplicationApprovedEvent | 
Card status updated | 
CARD_TOP_UP | 
Card top-up completed | TopUpCompletedEvent | 
Balance updated, transaction recorded | 
CARD_BILL_TRANSACTION | 
Card transaction (purchase, refund, etc.) | TransactionCompletedEvent | 
Balance updated, transaction recorded | 
What happens when a webhook is received:
- Transaction Recording: All webhooks create/update records in 
transactionstable - Balance Updates: Card balances are automatically updated from webhook data
 - Event Dispatching: Laravel events are dispatched for your listeners
 - API Verification: Optionally queries MusePay API for additional verification (configurable)
 
Available Events
CardCreatedEvent- Card has been createdCardActivatedEvent- Card has been activatedCardBlockedEvent- Card has been blockedTransactionCompletedEvent- Transaction completed successfully (fromCARD_BILL_TRANSACTION)TransactionFailedEvent- Transaction failedTopUpCompletedEvent- Card top-up completed (fromCARD_TOP_UP)KycApprovedEvent- KYC verification approvedKycRejectedEvent- KYC verification rejectedApplicationApprovedEvent- Card application approved (fromAPPLY_AUDIT)ApplicationRejectedEvent- Card application rejected (fromAPPLY_AUDIT)
Event Usage Example
namespace App\Listeners; use MuseWallet\SDK\Events\TransactionCompletedEvent; use App\Notifications\TransactionCompleted; class SendTransactionNotification { public function handle(TransactionCompletedEvent $event) { $transactionId = $event->getTransactionId(); $amount = $event->getAmount(); $currency = $event->getCurrency(); $merchantName = $event->getMerchantName(); // Send notification to user $user = User::where('card_id', $event->getCardId())->first(); $user->notify(new TransactionCompleted( $transactionId, $amount, $currency, $merchantName )); } }
Typed Responses (DTO)
All service methods return typed Data Transfer Objects for better IDE support and type safety:
Available Response Types
| Response Class | Used By | Properties | 
|---|---|---|
PartnerBalanceResponse | 
getPartnerBalance() | 
currency, balance, availableBalance, freezeBalance | 
CardHolderResponse | 
createCardHolder(), uploadKyc() | 
userId, userXid, kycStatus, email, firstName, lastName | 
CardApplicationResponse | 
applyCard(), queryApplyResult() | 
applyId, requestId, userId, status, cardId | 
CardInfoResponse | 
getCard(), activateCard() | 
cardId, cardNumber, status, balance, expiryMonth/Year | 
TopUpResponse | 
topUpCard() | 
requestId, cardId, amount, currency, orderNo | 
KycLinkResponse | 
generateKycLink() | 
userXid, link | 
Usage Examples
use MuseWallet\SDK\Facades\MuseWallet; // Get balance with typed response $balance = MuseWallet::getPartnerBalance('USDT'); // Access properties with autocomplete $available = $balance->availableBalance; // string|null $availableFloat = $balance->getAvailableBalanceFloat(); // float|null $isSuccess = $balance->isSuccessful(); // bool $rawData = $balance->data; // mixed (full API response) // Card application with typed response $application = MuseWallet::applyCard([...]); $applyId = $application->applyId; // string|null $status = $application->getStatus(); // string|null $cardId = $application->getCardId(); // string|null // Card info with typed response $card = MuseWallet::getCard($cardId, $userId); $masked = $card->getMaskedCardNumber(); // ****1234 $isActive = $card->isActive(); // bool $balance = $card->getBalanceFloat(); // float|null // KYC link with typed response $kycLink = MuseWallet::generateKycLink($userXid); if ($kycLink->hasLink()) { $url = $kycLink->getLink(); // string|null } // Top-up with typed response $topup = MuseWallet::topUpCard([...]); $amount = $topup->getAmountFloat(); // float|null $isSuccess = $topup->isTopUpSuccessful(); // bool
Benefits of Typed Responses
✅ IDE Autocomplete - Full IntelliSense support ✅ Type Safety - Catch errors at development time ✅ Documentation - Self-documenting code ✅ Helper Methods - Convenient getters and checks ✅ Raw Data Access - Full API response always available
Enums
The SDK provides several enum classes for type safety:
use MuseWallet\SDK\Enums\{ ApplyStatus, CardStatus, CardLevel, KycStatus, Currency, DocumentType }; // Check application status if (ApplyStatus::isSuccessful($status)) { // Handle successful application } // Check if currency is supported if (Currency::isSupported('USDT')) { // Process payment } // Get status label $label = KycStatus::label(KycStatus::APPROVED); // "Approved"
Database Model (Optional)
If you've published and run the migrations, you can use the MuseWalletCard model:
use MuseWallet\SDK\Models\MuseWalletCard; // Get user's cards $cards = MuseWalletCard::forUser($userId)->get(); // Get active cards $activeCards = MuseWalletCard::forUser($userId)->active()->get(); // Get card by status $lockedCards = MuseWalletCard::forUser($userId)->byStatus(CardStatus::LOCKED)->get(); // Get card by level $level1Cards = MuseWalletCard::forUser($userId)->byLevel(CardLevel::LEVEL_1)->get(); // Work with a card $card = MuseWalletCard::find($cardId); // Check card status if ($card->isActive()) { // Card is active } if ($card->canBeActivated()) { // Card can be activated } if ($card->isUsable()) { // Card is usable } // Get masked card number $maskedNumber = $card->getMaskedCardNumber(); // ****1234 // Get labels $statusLabel = $card->getStatusLabel(); // "Active" $levelLabel = $card->getCardLevelLabel(); // "Level 1" $kycLabel = $card->getKycStatusLabel(); // "Approved" // Access user relationship $user = $card->user;
Model Features
- Automatic Encryption: Sensitive fields (
card_number,document_number) are automatically encrypted - Scopes: 
active(),forUser(),byStatus(),byLevel() - Helper Methods: 
isActive(),canBeActivated(),isUsable(),getMaskedCardNumber() - Relations: 
user()- BelongsTo relationship with your User model - Casts: Automatic casting for dates, decimals, and JSON fields
 
Error Handling
The SDK includes comprehensive error codes with descriptions:
use MuseWallet\SDK\Services\MuseWalletErrorCodes; try { $result = MuseWallet::applyCard($data); } catch (\MuseWallet\SDK\Exceptions\MuseWalletException $e) { $code = $e->getCode(); // Check if error is retryable if (MuseWalletErrorCodes::isRetryable($code)) { // Retry the operation } // Check if user action is required if (MuseWalletErrorCodes::requiresUserAction($code)) { // Notify user } // Get detailed error information $errorInfo = MuseWalletErrorCodes::get($code); // Returns: ['message' => '...', 'description' => '...', 'suggestion' => '...'] }
Testing
The SDK includes comprehensive tests:
# Run all tests composer test # Run with coverage composer test-coverage # Run static analysis composer analyse
Card Products Configuration
MusePay API does not provide an endpoint to retrieve card products. You must configure your product IDs in the config file or environment variables after receiving them from MusePay support.
// config/musewallet.php 'card_products' => [ 'basic' => env('MUSEWALLET_BASIC_CARD_PRODUCT_ID'), 'premium' => env('MUSEWALLET_PREMIUM_CARD_PRODUCT_ID'), 'business' => env('MUSEWALLET_BUSINESS_CARD_PRODUCT_ID'), ],
Caching
The SDK supports response caching for improved performance:
// Enable caching in config/musewallet.php 'cache' => [ 'enabled' => true, 'ttl' => 300, // 5 minutes 'prefix' => 'musewallet:', ],
Logging
Detailed logging can be enabled for debugging:
// config/musewallet.php 'logging' => [ 'enabled' => true, 'level' => 'info', 'channel' => 'stack', ],
Security
- All API requests are signed with RSA SHA1 signatures
 - Webhook signatures are verified before processing
 - Private keys should be stored securely in environment variables
 - Never commit private keys to version control
 
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
License
This package is open-sourced software licensed under the MIT license.
Support
For issues, questions, or contributions, please use the GitHub issue tracker.
Credits
- Artem Puzik
 - Based on MusePay Card API documentation
 
Changelog
Please see CHANGELOG for more information on what has changed recently.