Laravel AI SDK: Raw HTTP Responses &amp; Rate Limits | Mohamed Said        [  ![Mohamed Said](https://cdn.msaied.com/01KT78WE565VEMM3PSNQAAB0MH.png)   Mohamed Said Laravel Backend Engineer  ](https://msaied.com) [ Home ](https://msaied.com) [ Projects ](https://msaied.com/projects) [ Articles  ](https://msaied.com/articles) [ Certificates ](https://msaied.com/certificates) [ Contact ](https://msaied.com#contact-section) 

       [  ](https://github.com/EG-Mohamed)       

 [ Home ](https://msaied.com) [ Projects ](https://msaied.com/projects) [ Articles ](https://msaied.com/articles) [ Certificates ](https://msaied.com/certificates) [ Contact ](https://msaied.com#contact-section) 

  [ home ](https://msaied.com)    [ articles ](https://msaied.com/articles)    Laravel AI SDK: Access Raw HTTP Responses and Rate Limit Headers        On this page       1. [  What Changed in Laravel AI SDK v0.10.3 ](#what-changed-in-laravel-ai-sdk-v0103)
2. [  Per-Step Raw Responses ](#per-step-raw-responses)
3. [  Monitoring Rate Limits With an Event Listener ](#monitoring-rate-limits-with-an-event-listener)
4. [  Correlating Failures With the Provider ](#correlating-failures-with-the-provider)
5. [  When raw Is Null ](#when-coderawcode-is-null)
6. [  Testing Rate Limit Logic ](#testing-rate-limit-logic)
7. [  Key Takeaways ](#key-takeaways)

  ![Laravel AI SDK: Access Raw HTTP Responses and Rate Limit Headers](https://cdn.msaied.com/592/3264cc3744b008ba415780f2e0a9fccb.png)

 [  Laravel ](https://msaied.com/articles?category=laravel) [  AI ](https://msaied.com/articles?category=ai)  #Laravel AI   #AI SDK   #Rate Limiting   #HTTP Client   #Laravel  

 Laravel AI SDK: Access Raw HTTP Responses and Rate Limit Headers 
==================================================================

     21 Aug 2026      3 min read    ![Mohamed Said](https://cdn.msaied.com/01KT78WE565VEMM3PSNQAAB0MJ.jpg)  Mohamed Said  

       Table of contents

1. [  01   What Changed in Laravel AI SDK v0.10.3  ](#what-changed-in-laravel-ai-sdk-v0103)
2. [  02   Per-Step Raw Responses  ](#per-step-raw-responses)
3. [  03   Monitoring Rate Limits With an Event Listener  ](#monitoring-rate-limits-with-an-event-listener)
4. [  04   Correlating Failures With the Provider  ](#correlating-failures-with-the-provider)
5. [  05   When raw Is Null  ](#when-coderawcode-is-null)
6. [  06   Testing Rate Limit Logic  ](#testing-rate-limit-logic)
7. [  07   Key Takeaways  ](#key-takeaways)

 What Changed in Laravel AI SDK v0.10.3
--------------------------------------

Before v0.10.3, the Laravel AI SDK returned a typed response object with shared properties like `$response->text`, `$response->usage`, and `$response->meta`. Anything outside that common shape — rate limit headers, provider-specific request IDs, or extra JSON fields — was simply unreachable without writing your own HTTP middleware.

Version 0.10.3, released on August 6, 2026, closes that gap. A new public `raw` property on every response holds the `Illuminate\Http\Client\Response` from the underlying HTTP call:

```php
$response = (new SupportAgent)->prompt('Summarize this document.');

$response->raw->header('x-ratelimit-remaining-requests');
$response->raw->json('id');

```

Because it is a standard Laravel HTTP client response, `header()`, `json()`, and `status()` all work exactly as they do after an `Http::get()` call.

Per-Step Raw Responses
----------------------

An agent that calls tools makes multiple round-trips. `$response->raw` reflects the final request — the one that produced the text you received. Every intermediate step also keeps its own `raw`:

```php
foreach ($response->steps as $step) {
    $step->raw?->header('x-ratelimit-remaining-tokens');
}

```

This matters for rate limit accounting: a five-step run consumed budget across five requests, and reading only the last header gives you an incomplete picture.

Monitoring Rate Limits With an Event Listener
---------------------------------------------

Instead of checking headers at every call site, you can centralise the logic in an event listener. The `AgentPrompted` event carries the full response:

```php
use Laravel\Ai\Events\AgentPrompted;

Event::listen(AgentPrompted::class, function (AgentPrompted $event) {
    $remaining = $event->response->raw?->header('x-ratelimit-remaining-requests');

    if ($remaining !== null && (int) $remaining < 10) {
        Log::warning('Provider request budget running low.', [
            'provider' => $event->response->meta->provider,
            'remaining' => $remaining,
        ]);
    }
});

```

One listener covers every agent run in your application.

Correlating Failures With the Provider
--------------------------------------

When a run produces unexpected output and you need to open a support ticket, providers ask for their own request ID. You can now log it without capturing the full prompt payload:

```php
Log::info('Agent run completed.', [
    'invocation' => $response->invocationId,
    'provider_request_id' => $response->raw?->header('request-id'),
]);

```

Header names vary by provider, so check the documentation for whichever one you are using.

When `raw` Is Null
------------------

The property is nullable — always use the null-safe operator `?->`. Four situations return null:

- **Streamed responses** (`$agent->stream()` and `AgentStreamed`) — the response is assembled from stream events, not a single response body.
- **AWS Bedrock** — the AWS SDK handles the HTTP call, so no `Illuminate\Http\Client\Response` is produced.
- **Serialized responses** — Guzzle streams cannot be serialized, so `raw` is dropped when a response passes through a queue or cache. Read the header before dispatching a job and pass the value explicitly.
- **Faked agents** — unless the fake is built with `withRawResponse()`.

Testing Rate Limit Logic
------------------------

Fake responses support `withRawResponse()` so you can simulate low-budget scenarios in tests:

```php
use GuzzleHttp\Psr7\Response as Psr7Response;
use Illuminate\Http\Client\Response;
use Laravel\Ai\Responses\TextResponse;

SupportAgent::fake([
    (new TextResponse('Hello', new Usage, new Meta))->withRawResponse(new Response(
        new Psr7Response(200, ['x-ratelimit-remaining-requests' => '99'], '{}')
    )),
]);

$response = (new SupportAgent)->prompt('Hi');
$response->raw->header('x-ratelimit-remaining-requests'); // '99'

```

Key Takeaways
-------------

- `$response->raw` is an `Illuminate\Http\Client\Response` available on every non-streamed, non-Bedrock response from v0.10.3 onward.
- Each step in a multi-step agent run has its own `raw`, giving you per-request rate limit data.
- The `AgentPrompted` event exposes `raw` for centralised monitoring without scattering header checks across your codebase.
- `raw` is null for streamed responses, Bedrock, serialized responses, and unfaked test agents.
- Use `withRawResponse()` (not `withRaw()`) to supply headers in fakes.

---

*Source: [Laravel AI: Get Raw HTTP Responses and Rate Limits — Laravel News](https://laravel-news.com/laravel-ai-raw-http-response)*

 Found this useful?

          [  ](https://twitter.com/intent/tweet?url=https%3A%2F%2Fmsaied.com%2Farticles%2Flaravel-ai-sdk-access-raw-http-responses-and-rate-limit-headers&text=Laravel+AI+SDK%3A+Access+Raw+HTTP+Responses+and+Rate+Limit+Headers) [  ](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fmsaied.com%2Farticles%2Flaravel-ai-sdk-access-raw-http-responses-and-rate-limit-headers) 

 Frequently Asked Questions 
----------------------------

  3 questions  

     Q01  Which providers populate `$response-&gt;raw` in the Laravel AI SDK?        All HTTP-based providers populate it: Anthropic, OpenAI, Azure OpenAI, DeepSeek, Gemini, Groq, Mistral, Ollama, OpenAI-compatible, OpenRouter, and xAI. AWS Bedrock does not, because the AWS SDK handles the HTTP call internally. 

      Q02  Why is `$response-&gt;raw` null after a queued or cached response?        The underlying Guzzle stream cannot be serialized. The SDK drops `raw` during `__serialize()` to avoid a `LogicException`. If you need a header value in a queued job, read it before dispatching and pass it as a constructor argument. 

      Q03  How do I test rate limit logic when `raw` is normally null in fakes?        Use `withRawResponse()` on a `TextResponse` fake, passing a `GuzzleHttp\Psr7\Response` with the headers you want to assert against. The method is `withRawResponse()`, not `withRaw()`. 

  Continue reading

 More Articles 
---------------

 [ View all    ](https://msaied.com/articles) 

 [ ![Filament v3.3.55 Released: CTRL/CMD+S Fix and CI Dependency Updates](https://cdn.msaied.com/589/31730941b34d9de9327a9bfc0652186e.png) filament laravel php 

### Filament v3.3.55 Released: CTRL/CMD+S Fix and CI Dependency Updates

Filament v3.3.55 ships a notable bug fix for the CTRL/CMD+S keyboard shortcut on create and edit pages, alongs...

  ![Mohamed Said](https://cdn.msaied.com/01KT78WE565VEMM3PSNQAAB0MJ.jpg)  Mohamed Said 

 24 Aug 2026     2 min read  

  Read    

 ](https://msaied.com/articles/filament-v3355-released-ctrlcmds-fix-and-ci-dependency-updates) [ ![Livewire v4.4.2 Released: Bug Fixes, Resilience Improvements, and Alpine 3.16.3](https://cdn.msaied.com/591/4e5121d9bddacf2c42ce4b1b39885c68.png) Livewire Laravel PHP 

### Livewire v4.4.2 Released: Bug Fixes, Resilience Improvements, and Alpine 3.16.3

Livewire v4.4.2 ships 18 pull requests covering exception hooks for computed properties, Eloquent cast fallbac...

  ![Mohamed Said](https://cdn.msaied.com/01KT78WE565VEMM3PSNQAAB0MJ.jpg)  Mohamed Said 

 24 Aug 2026     3 min read  

  Read    

 ](https://msaied.com/articles/livewire-v442-released-bug-fixes-resilience-improvements-and-alpine-3163) [ ![Livewire v3 Internals: Morph Markers, JS Hooks, and Alpine Integration](https://cdn.msaied.com/587/2c14265af448474f2da7319e924e95c1.png) livewire laravel alpine 

### Livewire v3 Internals: Morph Markers, JS Hooks, and Alpine Integration

Go beyond the docs: understand how Livewire v3 morphs the DOM, where Alpine state lives during re-renders, and...

  ![Mohamed Said](https://cdn.msaied.com/01KT78WE565VEMM3PSNQAAB0MJ.jpg)  Mohamed Said 

 24 Aug 2026     3 min read  

  Read    

 ](https://msaied.com/articles/livewire-v3-internals-morph-markers-js-hooks-and-alpine-integration-4) 

   [  ![Mohamed Said](https://cdn.msaied.com/01KT78WE565VEMM3PSNQAAB0MH.png)   Mohamed Said Laravel Backend Engineer  ](https://msaied.com)Senior Backend Engineer specializing in Laravel, scalable SaaS platforms, APIs, and cloud infrastructure. I build secure, high-performance web applications that help businesses grow.

Explore

- [Home](https://msaied.com)
- [Projects](https://msaied.com/projects)
- [Articles](https://msaied.com/articles)
- [Certificates](https://msaied.com/certificates)
- [Contact](https://msaied.com#contact-section)

Connect

- [   hello@msaied.com ](mailto:hello@msaied.com)
- [   +20 109 461 9204 ](tel:+201094619204)

© 2026 Mohamed Said. All rights reserved.

 [  ](https://github.com/EG-Mohamed) [  ](https://www.linkedin.com/in/msaiedm/) [  ](https://wa.me/201094619204) [  ](mailto:hello@msaied.com) [  ](https://drive.google.com/file/u/0/d/1MF20IPRJyzfy32mhEutjL5EpSls0w2Q8/view)
