Zum Hauptinhalt springen
tsecurity.de LIVE
Echtzeit-Radar & Feeds
Alle RSS Feeds
👥 Community & Social
YouTube Security VideosGoogle Chrome: Unfinished Projects: Solange’s Public Sculpture(21.09.2026 um 17:02 Uhr)
Windows Tipps & SecurityBlurry or pixelated video in Microsoft Teams(21.09.2026 um 14:34 Uhr)
Sicherheitslücken (CVE)USN-8791-1: Ghostscript vulnerability(21.09.2026 um 14:51 Uhr)
Sicherheitslücken (CVE)USN-8792-1: Memcached vulnerability(21.09.2026 um 15:02 Uhr)
Sichere ProgrammierungI stopped rewriting the same Electron boilerplate — so I packaged it(21.09.2026 um 17:28 Uhr)
YouTube Security VideosGoogle Chrome: Unfinished Projects: Solange’s Public Sculpture(21.09.2026 um 17:02 Uhr)
Windows Tipps & SecurityBlurry or pixelated video in Microsoft Teams(21.09.2026 um 14:34 Uhr)
Sicherheitslücken (CVE)USN-8791-1: Ghostscript vulnerability(21.09.2026 um 14:51 Uhr)
Sicherheitslücken (CVE)USN-8792-1: Memcached vulnerability(21.09.2026 um 15:02 Uhr)
Sichere ProgrammierungI stopped rewriting the same Electron boilerplate — so I packaged it(21.09.2026 um 17:28 Uhr)
Intelligence View
⚡ tsecurity.de Intelligence

Integrating Claude/OpenAI API into a Laravel App: A Practical Guide

After 12+ years of building PHP applications, I recently added AI-powered features to a production Laravel dashboard — automatic report summaries generated from raw analytics data. What surprised me wasn't how hard it was. It was how l…

0
↗ Quelle (dev.to)
Reagiere als Erste:r — dein Feedback zählt!

After 12+ years of building PHP applications, I recently added AI-powered features to a production Laravel dashboard — automatic report summaries generated from raw analytics data. What surprised me wasn't how hard it was. It was how little good PHP-focused content exists on this topic. Almost every LLM tutorial assumes you're writing Python.



So here's the guide I wish I had: integrating the Claude API and OpenAI API into a Laravel app, with a clean architecture you can actually ship to production.



What we'll build: a ReportSummaryService that takes raw data and returns a human-readable summary — with a driver pattern so you can switch between Claude and OpenAI with one config change.









Step 1: Get Your API Keys





Add them to your .env:




AI_PROVIDER=claude

ANTHROPIC_API_KEY=sk-ant-xxxxx
ANTHROPIC_MODEL=claude-sonnet-4-6

OPENAI_API_KEY=sk-xxxxx
OPENAI_MODEL=gpt-5-mini






⚠️ Never hardcode API keys. Never commit them. If you've ever pushed a key to Git, rotate it immediately. (You know this. I'm saying it anyway.)



Now register them in config/services.php — this is the Laravel way, so you can use config() everywhere and benefit from config caching:




'anthropic' => [
'key' => env('ANTHROPIC_API_KEY'),
'model' => env('ANTHROPIC_MODEL', 'claude-sonnet-4-6'),
],

'openai' => [
'key' => env('OPENAI_API_KEY'),
'model' => env('OPENAI_MODEL', 'gpt-5-mini'),
],

'ai' => [
'provider' => env('AI_PROVIDER', 'claude'),
],












Step 2: Understand the Two APIs (They're 95% Similar)



Both are simple REST APIs. You POST JSON, you get JSON back.



Claude (Messages API):




POST https://api.anthropic.com/v1/messages
Headers:
x-api-key: YOUR_KEY
anthropic-version: 2023-06-01
content-type: application/json






OpenAI (Chat Completions API):




POST https://api.openai.com/v1/chat/completions
Headers:
Authorization: Bearer YOUR_KEY
content-type: application/json






The key differences that trip people up:






































Claude OpenAI
Auth header x-api-key Authorization: Bearer
Extra header
anthropic-version required
max_tokens Required Optional
System prompt Top-level system field A message with role: system
Response text content[0].text choices[0].message.content


That's it. Once you know these five differences, you know both APIs.









Step 3: Build the Contract + Drivers



Instead of scattering Http::post() calls across controllers (we've all seen that codebase), let's define a contract:




<?php
// app/Services/AI/AiClientInterface.php

namespace App\Services\AI;

interface AiClientInterface
{
public function complete(string $systemPrompt, string $userMessage, int $maxTokens = 1024): string;
}









The Claude driver



Laravel's HTTP client makes this beautifully clean — no cURL boilerplate:




<?php
// app/Services/AI/ClaudeClient.php

namespace App\Services\AI;

use Illuminate\Support\Facades\Http;
use RuntimeException;

class ClaudeClient implements AiClientInterface
{
public function complete(string $systemPrompt, string $userMessage, int $maxTokens = 1024): string
{
$response = Http::withHeaders([
'x-api-key' => config('services.anthropic.key'),
'anthropic-version' => '2023-06-01',
])
->timeout(60)
->retry(2, 500, function ($exception) {
// Only retry on rate limits (429) or server errors (5xx)
return $exception->response?->status() >= 429;
})
->post('https://api.anthropic.com/v1/messages', [
'model' => config('services.anthropic.model'),
'max_tokens' => $maxTokens, // required by Claude
'system' => $systemPrompt,
'messages' => [
['role' => 'user', 'content' => $userMessage],
],
]);

if ($response->failed()) {
throw new RuntimeException(
'Claude API error: ' . $response->json('error.message', 'Unknown error')
);
}

return $response->json('content.0.text', '');
}
}









The OpenAI driver






<?php
// app/Services/AI/OpenAiClient.php

namespace App\Services\AI;

use Illuminate\Support\Facades\Http;
use RuntimeException;

class OpenAiClient implements AiClientInterface
{
public function complete(string $systemPrompt, string $userMessage, int $maxTokens = 1024): string
{
$response = Http::withToken(config('services.openai.key'))
->timeout(60)
->retry(2, 500, function ($exception) {
return $exception->response?->status() >= 429;
})
->post('https://api.openai.com/v1/chat/completions', [
'model' => config('services.openai.model'),
'max_completion_tokens' => $maxTokens,
'messages' => [
['role' => 'system', 'content' => $systemPrompt],
['role' => 'user', 'content' => $userMessage],
],
]);

if ($response->failed()) {
throw new RuntimeException(
'OpenAI API error: ' . $response->json('error.message', 'Unknown error')
);
}

return $response->json('choices.0.message.content', '');
}
}






Notice how much heavy lifting Laravel does here: timeout(), retry() with a conditional callback, withToken(), and dot-notation access into the JSON response. This is why I love this framework.









Step 4: Bind the Driver in a Service Provider



Now the magic — one config value decides which provider your entire app uses:




<?php
// app/Providers/AppServiceProvider.php

use App\Services\AI\AiClientInterface;
use App\Services\AI\ClaudeClient;
use App\Services\AI\OpenAiClient;

public function register(): void
{
$this->app->bind(AiClientInterface::class, function () {
return match (config('services.ai.provider')) {
'openai' => new OpenAiClient(),
default => new ClaudeClient(),
};
});
}






Switch providers by changing one line in .env. No code changes. If one provider has an outage or a price change, you flip a switch. This alone is worth the abstraction.









Step 5: Build a Real Feature



Here's a realistic use case from my own work: summarizing daily analytics data into a readable report for management.




<?php
// app/Services/ReportSummaryService.php

namespace App\Services;

use App\Services\AI\AiClientInterface;

class ReportSummaryService
{
public function __construct(
private AiClientInterface $ai
) {}

public function summarize(array $reportData): string
{
$systemPrompt = <<<PROMPT
You are a business analyst. Summarize the analytics data you receive
into 3-4 concise sentences for a non-technical manager.
Highlight the most important trend first. Do not use bullet points.
PROMPT;


return $this->ai->complete(
systemPrompt: $systemPrompt,
userMessage: 'Summarize this data: ' . json_encode($reportData),
maxTokens: 500
);
}
}






And the controller — thin, as it should be:




<?php
// app/Http/Controllers/ReportController.php

namespace App\Http\Controllers;

use App\Services\ReportSummaryService;
use Illuminate\Http\JsonResponse;

class ReportController extends Controller
{
public function summary(ReportSummaryService $summaryService): JsonResponse
{
$data = [
'total_visitors' => 12480,
'conversion_rate' => '3.2%',
'top_store' => 'Hyderabad Main Branch',
'change_vs_last_week' => '+14%',
];

return response()->json([
'summary' => $summaryService->summarize($data),
]);
}
}






Laravel's container injects everything. Your controller doesn't know or care whether Claude or OpenAI wrote the summary.









Step 6: Production Hardening (The Part Tutorials Skip)






Cache aggressively



LLM calls are slow (1–10 seconds) and cost money. If the input hasn't changed, don't call the API again:




use Illuminate\Support\Facades\Cache;

public function summarize(array $reportData): string
{
$cacheKey = 'report-summary:' . md5(json_encode($reportData));

return Cache::remember($cacheKey, now()->addHours(6), function () use ($reportData) {
return $this->ai->complete(/* ... */);
});
}






In my case this cut API costs by roughly 70% — most users request the same report multiple times a day.






Move long tasks to queues



Never make a user's HTTP request wait 10 seconds for an LLM. Dispatch a queued job, store the result, notify when ready:




GenerateReportSummary::dispatch($reportId);






If you're already running Laravel queues (Redis/database driver), this is a 15-minute change.






Handle failures gracefully



LLM APIs will fail sometimes — rate limits, overloaded servers, timeouts. The retry() calls in our drivers handle transient errors, but always wrap the feature so your app degrades gracefully:




try {
$summary = $summaryService->summarize($data);
} catch (RuntimeException $e) {
Log::warning('AI summary failed', ['error' => $e->getMessage()]);
$summary = null; // UI shows the raw data table instead
}






The AI feature should be an enhancement, not a single point of failure.






Control your costs





  • Set max_tokens deliberately. It caps your output cost per request.


  • Use smaller models for simple tasks. Summaries, classification, and extraction rarely need the flagship models — Claude Haiku or a mini-tier OpenAI model is often 10x cheaper and plenty good.


  • Set spend limits in both provider dashboards before you ship. Trust me on this one.


  • Log token usage. Both APIs return a usage object in the response — store it, so you know exactly what each feature costs.









What About the Official SDKs?



Everything above uses Laravel's HTTP client so you can see exactly what's happening on the wire. For bigger projects, consider:





  • Anthropic's official PHP SDK: composer require anthropic-ai/sdk guzzlehttp/guzzle (requires PHP 8.1+) — handles streaming, pagination, and retries for you


  • openai-php/laravel: a popular community package with a Laravel-native facade



I'd still recommend writing the raw version once, like we did here. Understanding the actual API makes debugging SDK issues far easier later.









Wrapping Up



The full picture:




  1. Keys in .env, referenced via config/services.php

  2. An AiClientInterface contract with a driver per provider

  3. Container binding so one env variable switches providers

  4. Thin controllers, logic in services

  5. Cache + queues + graceful failure for production



None of this is exotic — it's the same clean Laravel architecture you already use, applied to a new kind of API. That's the real takeaway: you don't need to learn Python to build AI features. Your PHP skills transfer directly.



In an upcoming post, I'll cover streaming responses to the browser (so summaries appear word-by-word, ChatGPT-style) using Laravel and Server-Sent Events. Follow me if you'd like to catch that one.






Have you added AI features to a PHP app? What did you use — raw HTTP, an SDK, or something else? I'd love to hear about it in the comments. 👇

Ähnliche Beiträge
🔍 Verwandte News

Auch interessante Nachrichten Integrating Claude/OpenAI API into a Laravel App: A Practical Guide

Thematisch verwandte Begriffe: Integrating, ClaudeOpenAI, into, Laravel · 6 Treffer

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Zum Aktualisieren ziehen
ZERO-DAY CVE-2026-82412 | ntopng is a web-based network traffic monitoring application. Prior to 6…
Advisory →
TTS Reader • tsecurity.de Voice
tsecurity.de Icon
tsecurity.de App
Offline-Lesen, Eilmeldungen & 0ms Ladezeit

Installiere tsecurity.de direkt auf deinen Home-Bildschirm für das ultimative Vollbild-Magazinerlebnis ohne Browser-Leisten.

Nächster Beitrag
Themen-Radar & Intelligence Matrix
Echtzeit-Taxonomie nach Angriffsvektoren & Plattformen

tsecurity.de Live Threat Radar

🔴 LIVE RADAR
MONITORING
AKTIV
CVE-DATENBANK
LIVE
🔍
Community Radar & Live Chat
Sentinel Bot online • Live-Stream
Dein Cluster: Security Explorer
Match:
lädt…
Verbindung zum Community-Stream wird aufgebaut...
Bearbeitungsmodus — Senden überschreibt deine Nachricht
Community-Puls — was gerade passiert
lädt…
Aktivitäten deiner Analysten
lädt…
Neues Thema oder Eilmeldung einreichen

Reiche interessante Links, Zero-Days oder Debatten ein. Die Community entscheidet per Upvote über die Veröffentlichung.

Heiß diskutierte Einreichungen
🔖 Gespeicherte Artikel
📂 Keine gespeicherten Artikel vorhanden.
Zurück Ziehen Vor
Links: vorheriger Artikel Rechts: nächster Artikel unten: schließen
News NIS-2 Frühwarnung Tier-1 Intel ⏱️ 3 Min vor 10 Min
Artikeldaten werden geladen...

Zurück: vorheriger Vor: nächster
↗ Original-Quelle
Social Reaktionen Deine Reaktion zählt
Einstufung & Relevanz-Poll 0 Stimmen
In sozialen Netzwerken teilen 1-Klick