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://www.msaied.com) [ Home ](https://www.msaied.com) [ Projects ](https://www.msaied.com/projects) [ Articles  ](https://www.msaied.com/articles) [ Certificates ](https://www.msaied.com/certificates) [ Contact ](https://www.msaied.com#contact-section) 

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

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

  [ home ](https://www.msaied.com)    [ articles ](https://www.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://www.msaied.com/articles?category=laravel) [  AI ](https://www.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%2Fwww.msaied.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%2Fwww.msaied.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://www.msaied.com/articles) 

 [ ![Laravel Queues at Scale: Backpressure, Dead-Letter Queues, and Graceful Degradation](https://cdn.msaied.com/602/fcffaaa5442f84486d6059eaa4106d26.png) laravel queues reliability 

### Laravel Queues at Scale: Backpressure, Dead-Letter Queues, and Graceful Degradation

Beyond basic queue workers: learn how to implement backpressure signals, dead-letter queues, and graceful degr...

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

 28 Aug 2026     3 min read  

  Read    

 ](https://www.msaied.com/articles/laravel-queues-at-scale-backpressure-dead-letter-queues-and-graceful-degradation) [ ![Mask Query Bindings in Laravel Exception Messages](https://cdn.msaied.com/603/3011313796d00cd5c4e1ead00e1e9ba1.png) Laravel Security QueryException 

### Mask Query Bindings in Laravel Exception Messages

Laravel 13.27 adds a per-connection option to prevent bound query values from appearing in QueryException mess...

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

 27 Aug 2026     3 min read  

  Read    

 ](https://www.msaied.com/articles/mask-query-bindings-in-laravel-exception-messages) [ ![whereBinary(): How to Run Case-Sensitive MySQL Queries in Laravel 13.27](https://cdn.msaied.com/600/0c7655400b43d3b85d1d1e9d0f4c8094.png) Laravel MySQL Query Builder 

### whereBinary(): How to Run Case-Sensitive MySQL Queries in Laravel 13.27

Laravel 13.27 adds whereBinary(), orWhereBinary(), whereNotBinary(), and orWhereNotBinary() — clean query-buil...

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

 26 Aug 2026     4 min read  

  Read    

 ](https://www.msaied.com/articles/wherebinary-how-to-run-case-sensitive-mysql-queries-in-laravel-1327) 

   [  ![Mohamed Said](https://cdn.msaied.com/01KT78WE565VEMM3PSNQAAB0MH.png)   Mohamed Said Laravel Backend Engineer  ](https://www.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://www.msaied.com)
- [Projects](https://www.msaied.com/projects)
- [Articles](https://www.msaied.com/articles)
- [Certificates](https://www.msaied.com/certificates)
- [Contact](https://www.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)
