[6 tools called] Here’s how Klook payments are wired through Trektoo today: --- ### 1. Front‑end flow (activities → payment) 1. **Activity booking form (`frontend/src/app/activities-booking/page.jsx`)** collects traveller info and, once validated, calls the backend to create the Klook order and payment intent. The payload contains: - Klook order metadata (`order_id`, `agent_order_id`, package info, schedule, quantities, markup, etc.) - Passenger/contact details (all fields required by Klook’s `otherinfo`) 2. When the user lands on `/payment/checkout`, (`frontend/src/app/payment/checkout/page.jsx`) it: - Requires login (via `useAuth`) because every request must include the stored `authToken`. - Restores the order/amount from localStorage (`getBookingStorageItem('klookPayment')`) or requests it from the API (`GET /klook/order-status/{orderId}` with `Authorization: Bearer …`). - Shows a card form placeholder; the actual payment is mocked in UI, but the real capture happens server-side once Stripe confirms. - After “Complete Payment” it clears local storage and redirects to `/thankyou`. `ThankYouContent.jsx` then calls backend endpoints to fetch final booking/payment status and generate vouchers. --- ### 2. Backend orchestration (`app/Http/Controllers/Api/PaymentController.php`) Key pieces: - `createKlookPaymentIntent()` (lines ~300+) - Validates the rich payload (order ids, activity details, passengers, amounts, markup). - Creates a `Booking` record (type `activity`) and persists passengers. - Creates a `Payment` row via `PaymentManager`, storing Trektoo’s charge amount vs. Klook’s net price. - Calls `StripeService::createPaymentIntent()` to get `client_secret` + `payment_intent_id`. - Returns the intent info to the frontend. - `PaymentManager` & `StripeService` (under `app/Services/Payment/`) encapsulate Stripe API usage (intent creation, confirmation, refunds). - `StripeWebhookController` listens for `payment_intent.succeeded`. When Stripe confirms: 1. `PaymentManager` marks the Trektoo payment as paid. 2. It immediately calls `$klookService->payWithBalance($orderNo)` so Trektoo pays Klook’s supplier balance. 3. It fetches Klook order details (`getOrderDetail`) to capture `total_amount`/`currency`, stores them on the `Payment` (`klook_paid_amount`, `klook_paid_currency`). 4. Triggers `BookingConfirmationNotification` and queues voucher generation. There’s also a queued job (`ProcessKlookBalancePayment`) that can retry paying Klook with balance if the webhook step fails. --- ### 3. Klook service layer `App\Services\Klook\KlookApiService` wraps all Klook REST endpoints (create order, pay with balance, get order detail, etc.). `PaymentController` and other controllers rely on this service to: - Create orders (`createOrder`), - Pay with agent balance (`payWithBalance`), - Fetch order details for reconciliation (`getOrderDetail`), - Retrieve agent balance (`getBalance`). Those responses feed into `Payment`/`Booking` models. The `Payment` model has helpers and casts (`klook_paid_amount`, `klook_paid_currency`) plus profit calculations once Trektoo’s markup is compared to the Klook paid amount. --- ### 4. Authentication / tokens On the frontend, every call is made with `secureApiClient`. The request interceptor (`frontend/src/lib/api/secureApiClient.js`) automatically injects `Authorization: Bearer ` from `localStorage`. That’s why payment pages redirect unauthenticated users to `/login?redirect=…`. --- ### 5. Summary of the payment timeline 1. **User fills activity form →** front-end hits `POST /api/payments/klook/create-intent`. 2. **Controller creates Trektoo booking & payment, then Stripe intent.** 3. **User completes Stripe checkout → Stripe webhook fires →** Trektoo marks payment paid. 4. **Webhook / job calls Klook `payWithBalance`** to settle the supplier order. 5. **Order details saved →** `Payment` updated with Klook settlement amounts. 6. **Notifications & thank-you flows** consume the stored data, generate vouchers, etc. That’s the full pipeline currently powering Klook payments in the project.