wiseApiKey = env('WISE_API_KEY'); $this->profileId = env('WISE_PROFILE_ID'); // Your Wise business/profile ID $this->wiseClient = new Client([ 'base_uri' => 'https://api.wise.com/v1/', 'headers' => [ 'Authorization' => 'Bearer ' . $this->wiseApiKey, 'Content-Type' => 'application/json', ], ]); } public function createTransfer(Request $request) { // Validate the incoming request data $validatedData = $request->validate([ 'amount' => 'required|numeric|min:0.01', 'source_currency' => 'required|string|size:3', 'target_currency' => 'required|string|size:3', 'recipient_name' => 'required|string|max:255', 'recipient_email' => 'required|email', 'recipient_account_number' => 'required|string', 'recipient_bank_code' => 'sometimes|string', // Needed for some countries 'recipient_address' => 'sometimes|array', 'reason' => 'sometimes|string|max:255', ]); try { // Create a new Payment record $payment = new Payment([ 'amount' => $validatedData['amount'], 'currency' => $validatedData['source_currency'], 'target_currency' => $validatedData['target_currency'], 'recipient_name' => $validatedData['recipient_name'], 'recipient_email' => $validatedData['recipient_email'], 'status' => 'pending', 'client_session_id' => $request->client_session_id ?? uniqid('wise_', true) ]); $payment->save(); // Create recipient account $recipient = $this->createRecipient($validatedData); // Create quote $quote = $this->createQuote($validatedData); // Create transfer $transfer = $this->createTransferWise($quote, $recipient, $validatedData); // Fund the transfer $this->fundTransfer($transfer['id']); // Update the Payment record $payment->wise_transfer_id = $transfer['id']; $payment->wise_recipient_id = $recipient['id']; $payment->wise_quote_id = $quote['id']; $payment->status = 'processing'; $payment->save(); return response()->json([ 'success' => true, 'message' => 'Transfer initiated successfully.', 'transfer_id' => $transfer['id'], 'payment_id' => $payment->id ]); } catch (ClientException $e) { $response = $e->getResponse(); $body = json_decode($response->getBody()->getContents(), true); Log::error('Wise Client Error:', [ 'code' => $e->getCode(), 'message' => $e->getMessage(), 'details' => $body ]); if (isset($payment)) { $payment->status = 'failed'; $payment->error_message = $e->getMessage(); $payment->save(); } return response()->json([ 'success' => false, 'message' => 'Wise API failed to process the request.', 'error' => $body['errors'] ?? $e->getMessage() ], 400); } catch (\Exception $e) { Log::error('General Wise API Error:', [ 'message' => $e->getMessage(), 'trace' => $e->getTraceAsString() ]); if (isset($payment)) { $payment->status = 'failed'; $payment->error_message = $e->getMessage(); $payment->save(); } return response()->json([ 'success' => false, 'message' => 'An unexpected error occurred.', 'error' => $e->getMessage() ], 500); } } public function handleWebhook(Request $request) { // Verify the webhook signature if needed $payload = $request->all(); Log::info('Wise Webhook Received:', $payload); if (isset($payload['data']['resource']['id'])) { $transferId = $payload['data']['resource']['id']; // Find the payment by transfer ID $payment = Payment::where('wise_transfer_id', $transferId)->first(); if ($payment) { $payment->status = $payload['data']['current_state'] ?? 'unknown'; $payment->save(); // You might want to trigger other actions based on status change } } return response()->json(['status' => 'ok']); } // Helper methods to interact with Wise API private function createRecipient($data) { $response = $this->wiseClient->post('accounts', [ 'json' => [ 'profile' => $this->profileId, 'accountHolderName' => $data['recipient_name'], 'currency' => $data['target_currency'], 'type' => 'email', // or 'sort_code', 'aba', 'iban' etc. based on country 'details' => [ 'email' => $data['recipient_email'], // Add more details based on account type and country 'legalType' => 'PRIVATE', // 'accountNumber' => $data['recipient_account_number'], // 'bankCode' => $data['recipient_bank_code'] ?? null, ] ], ]); return json_decode($response->getBody(), true); } private function createQuote($data) { $response = $this->wiseClient->post('quotes', [ 'json' => [ 'profile' => $this->profileId, 'source' => $data['source_currency'], 'target' => $data['target_currency'], 'rateType' => 'FIXED', // or 'FLOAT' 'sourceAmount' => $data['amount'], 'type' => 'BALANCE_PAYOUT' // or 'BALANCE_CONVERSION' ], ]); return json_decode($response->getBody(), true); } private function createTransferWise($quote, $recipient, $data) { $response = $this->wiseClient->post('transfers', [ 'json' => [ 'targetAccount' => $recipient['id'], 'quote' => $quote['id'], 'customerTransactionId' => uniqid('cti_', true), 'details' => [ 'reference' => $data['reason'] ?? 'Payment for services', 'transferPurpose' => $data['reason'] ?? 'Payment for services', ] ], ]); return json_decode($response->getBody(), true); } private function fundTransfer($transferId) { // Check if the transfer requires funding $transfer = $this->wiseClient->get("transfers/{$transferId}"); $transferData = json_decode($transfer->getBody(), true); if ($transferData['status'] === 'pending') { // Fund the transfer from your balance $this->wiseClient->post("transfers/{$transferId}/payments", [ 'json' => [ 'type' => 'BALANCE', 'profile' => $this->profileId ] ]); } } // Additional helper method to check transfer status public function checkTransferStatus($paymentId) { $payment = Payment::findOrFail($paymentId); try { $response = $this->wiseClient->get("transfers/{$payment->wise_transfer_id}"); $transferData = json_decode($response->getBody(), true); $payment->status = $transferData['status']; $payment->save(); return response()->json([ 'success' => true, 'status' => $transferData['status'] ]); } catch (\Exception $e) { return response()->json([ 'success' => false, 'message' => 'Failed to check transfer status' ], 500); } } }