A cache keys on the URL. If the response depends on anything else — an Accept header, a language, an authorisation token — the cache will serve one variant to everyone unless told what else matters.
return response()->json($data)
->header('Vary', 'Accept, Accept-Language')
->header('Cache-Control', 'public, s-maxage=300');
Vary: Authorization looks like the safe way to cache authenticated responses and is not — it fragments the cache per token and stores private data in a shared cache, so private is the correct answer there instead. Varying on User-Agent is the classic mistake: it is effectively unique per visitor and disables caching entirely while appearing to work.