Laravel AI SDK: Raw HTTP Responses &amp; Rate Limits | Mohamed Said       [Skip to content](#main)  [ ![](https://cdn.msaied.com/01KT78WE565VEMM3PSNQAAB0MH.png) Mohamed SaidLaravel Backend Engineer ](https://www.msaied.com/public) - [Home](https://www.msaied.com/public)
- [Projects](https://www.msaied.com/public/projects)
- [Articles](https://www.msaied.com/public/articles)
- [Certificates](https://www.msaied.com/public/certificates)
- [About](https://www.msaied.com/public#about)

           [  Contact](https://www.msaied.com/public#contact) Menu 

Menu
----

Close 

 - [HomeStart here](https://www.msaied.com/public)
- [ProjectsCase studies](https://www.msaied.com/public/projects)
- [ArticlesEngineering notes](https://www.msaied.com/public/articles)
- [CertificatesCredentials](https://www.msaied.com/public/certificates)
- [AboutHow I work](https://www.msaied.com/public#about)
- [ContactGet in touch](https://www.msaied.com/public#contact)

  [Start a conversation](https://www.msaied.com/public#contact) [WhatsApp](https://wa.me/201094619204) [Email](mailto:hello@msaied.com) 

 1. [Home](https://www.msaied.com/public)
2. /
3. [Articles](https://www.msaied.com/public/articles)
4. /
5. [Laravel](https://www.msaied.com/public/articles?category=laravel)
6. /
7. Laravel AI SDK: Access Raw HTTP Responses and Rate Limit Headers

   [Laravel](https://www.msaied.com/public/articles?category=laravel) [AI](https://www.msaied.com/public/articles?category=ai) 

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

 Laravel AI SDK v0.10.3 adds a `raw` property to every response, exposing the underlying `Illuminate\\Http\\Client\\Response` so you can read rate limit headers, provider request IDs, and any other HTTP metadata directly.

 ![](https://cdn.msaied.com/01M22N44A70A5MC2S599JP0MPH.webp) [Mohamed Said](https://www.msaied.com/public#person) Published 21 Aug 2026 · Updated 25 Aug 2026 · 3 min read

ShareCopy linkCopied

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

  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)

 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)*

- [Laravel AI](https://www.msaied.com/public/articles?search=Laravel%20AI)
- [AI SDK](https://www.msaied.com/public/articles?search=AI%20SDK)
- [Rate Limiting](https://www.msaied.com/public/articles?search=Rate%20Limiting)
- [HTTP Client](https://www.msaied.com/public/articles?search=HTTP%20Client)
- [Laravel](https://www.msaied.com/public/articles?search=Laravel)

 Frequently asked questions 
---------------------------

  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.

   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.

   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()`.

   ![Mohamed Said](https://cdn.msaied.com/01M22N44A70A5MC2S599JP0MPH.webp)About the author
----------------

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

[About](https://www.msaied.com/public#about) [GitHub ↗](https://github.com/EG-Mohamed) [LinkedIn ↗](https://www.linkedin.com/in/msaiedm/) [WhatsApp ↗](https://wa.me/201094619204) [Email Address ↗](mailto:hello@msaied.com) [My CV ↗](https://drive.google.com/file/u/0/d/1MF20IPRJyzfy32mhEutjL5EpSls0w2Q8/view)  

   [Previous articleDeftform: A Simple Laravel-Powered Form Builder That Stays Out of Your Way](https://www.msaied.com/public/articles/deftform-a-simple-laravel-powered-form-builder-that-stays-out-of-your-way) [Next articleLaravel AI v0.11: Trace Agent Runs With Lifecycle Events](https://www.msaied.com/public/articles/laravel-ai-v011-trace-agent-runs-with-lifecycle-events)  

   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)

 ###  Have a technical challenge?

 Tell me what you’re building. I reply within two working days.

[Start a conversation](https://www.msaied.com/public#contact) 

   Related articles
-----------------

 [ ![](https://cdn.msaied.com/740/cce86edc21eddcbdd2f2454fadaf9c70.png)  · 3 min read### The Pipeline Pattern in Laravel: Custom Pipelines Beyond Middleware

5 Oct 2026 ](https://www.msaied.com/public/articles/the-pipeline-pattern-in-laravel-custom-pipelines-beyond-middleware-1) [ ![](https://cdn.msaied.com/739/2d6897fdcdcf090613f96f72a64b8a78.png)  · 4 min read### MySQL Full-Text Search in Laravel: Indexes, Relevance Scoring, and Boolean Mode

4 Oct 2026 ](https://www.msaied.com/public/articles/mysql-full-text-search-in-laravel-indexes-relevance-scoring-and-boolean-mode) [ ![](https://cdn.msaied.com/738/073696a3fefe18bec825beec5ac658f5.png)  · 4 min read### Laravel Queue Rate-Limited Middleware: Throttling Jobs Without Losing Work

4 Oct 2026 ](https://www.msaied.com/public/articles/laravel-queue-rate-limited-middleware-throttling-jobs-without-losing-work) 

  Have a technical challenge?
----------------------------

Tell me what you’re building. I reply within two working days.

 [Discuss your project ↗](https://www.msaied.com/public#contact) 

  © 2026 Mohamed Said · Built with Laravel, meant to last.Senior Backend Engineer specializing in Laravel, scalable SaaS platforms, APIs, and cloud infrastructure. I build secure, high-performance web applications that help businesses grow.

 - [Home](https://www.msaied.com/public)
- [Articles](https://www.msaied.com/public/articles)
- [Certificates](https://www.msaied.com/public/certificates)
- [GitHub](https://github.com/EG-Mohamed)
- [LinkedIn](https://www.linkedin.com/in/msaiedm/)
- [WhatsApp](https://wa.me/201094619204)
- [Email Address](mailto:hello@msaied.com)
- [My CV](https://drive.google.com/file/u/0/d/1MF20IPRJyzfy32mhEutjL5EpSls0w2Q8/view)
- [Sitemap](https://www.msaied.com/public/sitemap.xml)
