middleware(function ($request, $next) { $provided = $this->extractToken($request); $expected = config('services.vault_api.token'); if (!$expected || !hash_equals((string) $expected, (string) $provided)) { return response()->json(['message' => 'Unauthorized'], 401); } return $next($request); }); } private function extractToken(Request $request): ?string { $auth = $request->header('Authorization'); if ($auth && str_starts_with($auth, 'Bearer ')) { return substr($auth, 7); } return $request->query('api_token'); // fallback: allow ?api_token= } /** * GET /api/users/{id}/vault */ public function showForUser(Request $request, int $id) { $perPage = min(200, max(1, (int) $request->query('per_page', 50))); try { $res = $this->client->get($request, "/users/{$id}/vault", [ 'per_page' => $perPage ], retry: true); if ($res->successful()) { return response()->json($res->json() ?: [], 200); } if ($res->clientError()) return $this->mapClientError($res); if ($res->serverError()) return $this->mapServiceUnavailable($res); return $this->mapBadGateway(); } catch (\Throwable $e) { return $this->mapBadGateway('API server not reachable'); } } /** * POST /api/users/{id}/vault/deposit */ public function depositForUser(Request $request, int $id) { $data = $request->validate([ 'amount' => ['required','string','regex:/^\d+(?:\.\d{1,4})?$/'], 'idempotency_key' => ['sometimes','nullable','string','max:64'], 'reason' => ['sometimes','nullable','string','max:255'], 'created_by' => ['sometimes','nullable','integer'], ]); // Pass through metadata we can gather; upstream decides usage $payload = [ 'amount' => $data['amount'], 'idempotency_key' => $data['idempotency_key'] ?? null, 'reason' => $data['reason'] ?? null, 'created_by' => $data['created_by'] ?? null, 'ip' => $request->ip(), 'user_agent' => $request->userAgent(), ]; try { $res = $this->client->post($request, "/users/{$id}/vault/deposit", $payload); if ($res->successful()) { return response()->json($res->json() ?: [], 201); } if ($res->clientError()) return $this->mapClientError($res); if ($res->serverError()) return $this->mapServiceUnavailable($res); return $this->mapBadGateway(); } catch (\Throwable $e) { return $this->mapBadGateway('API server not reachable'); } } /** * POST /api/users/{id}/vault/withdraw */ public function withdrawForUser(Request $request, int $id) { $data = $request->validate([ 'amount' => ['required','string','regex:/^\d+(?:\.\d{1,4})?$/'], 'idempotency_key' => ['sometimes','nullable','string','max:64'], 'reason' => ['sometimes','nullable','string','max:255'], 'created_by' => ['sometimes','nullable','integer'], ]); $payload = [ 'amount' => $data['amount'], 'idempotency_key' => $data['idempotency_key'] ?? null, 'reason' => $data['reason'] ?? null, 'created_by' => $data['created_by'] ?? null, 'ip' => $request->ip(), 'user_agent' => $request->userAgent(), ]; try { $res = $this->client->post($request, "/users/{$id}/vault/withdraw", $payload); if ($res->successful()) { return response()->json($res->json() ?: [], 201); } if ($res->clientError()) return $this->mapClientError($res); if ($res->serverError()) return $this->mapServiceUnavailable($res); return $this->mapBadGateway(); } catch (\Throwable $e) { return $this->mapBadGateway('API server not reachable'); } } }