refinder / laravel-sdk
Official Laravel SDK for Refinder AI Tools — SEO automation and AI-powered content optimization.
Installs: 5
Dependents: 0
Suggesters: 0
Security: 0
Stars: 0
Watchers: 0
Forks: 0
Open Issues: 0
pkg:composer/refinder/laravel-sdk
Requires
- php: ^8.2
- guzzlehttp/guzzle: ^7.0
- illuminate/http: ^11.0|^12.0
- illuminate/support: ^11.0|^12.0
Requires (Dev)
- orchestra/testbench: ^9.0|^10.0
- pestphp/pest: ^3.0
README
Official Laravel SDK for Refinder AI Tools
SEO automation and AI-powered content optimization for Laravel applications.
Installation • Quick Start • SEO Tool • API Reference • Error Handling • Testing
Overview
The Refinder Laravel SDK is a first-party Laravel package that integrates your application with the Refinder AI Tools platform. It provides:
- A clean Facade (
Refinder) for quick access to all features - Fully typed DTOs for all requests and responses
- Automatic authentication via API key (
X-API-Keyheader) - Built-in error handling with a custom exception hierarchy
- Event dispatching for tool executions (success & failure)
- Caching support for identical tool inputs
- Usage tracking helpers for monitoring quotas
- Full IDE autocompletion support via PHPDoc annotations
What Does the Refinder API Do?
Refinder AI Tools is an AI middleware platform that provides AI-powered tools as a service:
- Abstracts multiple LLM providers (OpenAI, DeepSeek, Alibaba Cloud Qwen, etc.) behind a unified interface
- Provides pluggable AI tools (starting with SEO)
- Manages subscriptions, usage quotas, and rate limiting
- Returns structured JSON outputs from all tools
Requirements
| Requirement | Version |
|---|---|
| PHP | >= 8.2 |
| Laravel | 11.x or 12.x |
| Guzzle | >= 7.0 |
Installation
composer require refinder/laravel-sdk
The package auto-registers its service provider and facade via Laravel's package discovery.
Publish Configuration
php artisan vendor:publish --tag=refinder-config
This creates config/refinder.php with all available options.
Environment Variables
Add the following to your .env file:
REFINDER_API_KEY=rfnd_your_api_key_here REFINDER_BASE_URL=https://api.refinder.ai/api/v1 REFINDER_TIMEOUT=120 REFINDER_RETRIES=2 REFINDER_CACHE_ENABLED=false REFINDER_CACHE_TTL=60 REFINDER_EVENTS=true
Required: Only
REFINDER_API_KEYis required. All other values have sensible defaults.
Quick Start
use Refinder\LaravelSdk\Facades\Refinder; // Execute SEO analysis $result = Refinder::seo()->execute([ 'content' => 'Your article content here...', 'content_type' => 'article', 'language' => 'en', ]); // Access the results echo $result->output->metaTitle; // "Optimized SEO Title..." echo $result->output->metaDescription; // "Meta description..." echo $result->output->seoScore->overall; // 75 (0-100) // Check if score is passing (>= 60) if ($result->output->seoScore->isPassing()) { echo "SEO score is good!"; }
Configuration
The full configuration file (config/refinder.php):
return [ // Your API key (required) 'api_key' => env('REFINDER_API_KEY'), // API base URL 'base_url' => env('REFINDER_BASE_URL', 'https://api.refinder.ai/api/v1'), // Request timeout in seconds (tool executions can take 10-30s) 'timeout' => env('REFINDER_TIMEOUT', 120), // Retry on 5xx/timeout errors (never retries 4xx) 'retries' => env('REFINDER_RETRIES', 2), 'retry_delay_ms' => env('REFINDER_RETRY_DELAY', 1000), // Response caching for identical inputs 'cache' => [ 'enabled' => env('REFINDER_CACHE_ENABLED', false), 'ttl' => env('REFINDER_CACHE_TTL', 60), // minutes 'prefix' => 'refinder_', ], // Dispatch Laravel events after tool executions 'events' => env('REFINDER_EVENTS', true), // Log channel (null = default channel) 'log_channel' => env('REFINDER_LOG_CHANNEL', null), ];
SEO Tool
The SEO tool is the primary feature of the Refinder platform. It analyzes content and generates comprehensive SEO recommendations.
Input Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
content |
string |
Yes | — | Text content to analyze (min 10 chars) |
url |
string |
No | null |
Page URL for additional context |
content_type |
string |
No | "page" |
One of: article, product, service, page, blog |
language |
string |
No | "en" |
Target language code (e.g., en, ar, fr) |
depth |
string |
No | "advanced" |
Analysis depth: basic, advanced, technical |
target_keywords |
array |
No | [] |
Specific keywords to optimize around |
brand_name |
string |
No | null |
Brand name for meta titles/headings |
industry |
string |
No | null |
Industry context for better optimization |
Depth Levels
| Level | Includes |
|---|---|
| basic | Meta title, meta description, primary keywords |
| advanced | Everything in basic + secondary/long-tail keywords, content analysis, heading suggestions, optimization suggestions, SEO scores |
| technical | Everything in advanced + schema markup, Open Graph tags, canonical URLs, content gap analysis |
Using the SeoInput DTO
use Refinder\LaravelSdk\DTOs\SeoInput; use Refinder\LaravelSdk\Facades\Refinder; $input = new SeoInput( content: $article->body, url: route('articles.show', $article), contentType: 'article', language: 'en', depth: 'advanced', targetKeywords: ['AI tools', 'machine learning'], brandName: 'MyBrand', industry: 'Technology', ); $result = Refinder::seo()->execute($input);
Shorthand Methods
// Basic analysis $result = Refinder::seo()->basic($content, 'en'); // Advanced analysis (default) $result = Refinder::seo()->advanced($content, 'en'); // Full technical analysis $result = Refinder::seo()->technical($content, 'en');
Working with SEO Output
$result = Refinder::seo()->execute(['content' => $text]); $seo = $result->output; // Meta tags echo $seo->metaTitle; // string (50-60 chars) echo $seo->metaDescription; // string (150-160 chars) // Keywords $seo->keywords->primary; // ['keyword1', 'keyword2', ...] $seo->keywords->secondary; // ['keyword3', 'keyword4', ...] $seo->keywords->longTail; // ['long tail phrase', ...] $seo->keywords->all(); // All keywords merged // Content Analysis $seo->contentAnalysis->readabilityScore; // 'excellent', 'good', 'needs_improvement' $seo->contentAnalysis->wordCountAssessment; // string $seo->contentAnalysis->contentQuality; // 'high', 'medium', 'low' $seo->contentAnalysis->keyTopicsCovered; // ['topic1', ...] // SEO Score (0-100) $seo->seoScore->overall; // 75 $seo->seoScore->content; // 70 $seo->seoScore->keywords; // 80 $seo->seoScore->structure; // 75 $seo->seoScore->isPassing(); // true (>= 60) // Optimization Suggestions foreach ($seo->optimizationSuggestions as $suggestion) { echo $suggestion->category; // 'content', 'technical', 'structure', 'keywords' echo $suggestion->priority; // 'high', 'medium', 'low' echo $suggestion->suggestion; // "Add structured data markup" echo $suggestion->details; // "Implementing JSON-LD..." $suggestion->isHighPriority(); // bool } // Heading Structure echo $seo->headingStructure->suggestedH1; // string $seo->headingStructure->suggestedH2s; // array of strings $seo->headingStructure->suggestedH3s; // array of strings // Execution metadata echo $result->id; // UUID echo $result->status; // 'completed' echo $result->usage->totalTokens; // 1276 echo $result->usage->executionTimeSeconds(); // 14.5 echo $result->model->name; // 'Qwen Plus' echo $result->model->provider; // 'alibaba'
API Reference
Platform Information
$platform = Refinder::me(); echo $platform->id; // 1 echo $platform->name; // "My Platform" echo $platform->slug; // "my-platform" echo $platform->website; // "https://example.com" echo $platform->description; // "Platform description" echo $platform->isActive; // true echo $platform->createdAt; // "2026-02-08T09:00:00+00:00"
Subscription Details
$sub = Refinder::subscription(); echo $sub->plan->name; // "Pro" echo $sub->plan->slug; // "pro" echo $sub->plan->maxRequestsPerMonth; // 1000 echo $sub->plan->maxRequestsPerDay; // 100 echo $sub->plan->features; // ['advanced_seo', 'api_access', ...] echo $sub->status; // "active" $sub->isActive(); // true $sub->isOnTrial(); // false
Usage Statistics
// Current month usage $usage = Refinder::usage(); // Custom date range $usage = Refinder::usage('2026-01-01', '2026-01-31'); echo $usage->totalRequests; // 47 echo $usage->totalTokens; // 62340 echo $usage->totalCost; // 0.12468 echo $usage->periodFrom; // "2026-02-01" echo $usage->periodTo; // "2026-02-08" // Daily breakdown foreach ($usage->daily as $day) { echo $day->date; // "2026-02-08" echo $day->tool; // "seo" echo $day->requestsCount; // 12 echo $day->tokensUsed; // 15600 echo $day->estimatedCost; // 0.0312 }
Execution History
// List executions (paginated) $executions = Refinder::executions(perPage: 10, page: 1); echo $executions->total; // 47 echo $executions->currentPage; // 1 echo $executions->lastPage; // 5 echo $executions->hasMorePages(); // true foreach ($executions->items as $exec) { echo $exec->id; // UUID echo $exec->tool; // "seo" echo $exec->status; // "completed" echo $exec->usage->totalTokens; // 1276 echo $exec->createdAt; // ISO 8601 string } // Get specific execution $exec = Refinder::execution('d47181d4-d26b-4224-a7f7-4c973b66f8fa'); if ($exec->isCompleted()) { echo $exec->output->metaTitle; }
Available Tools
$tools = Refinder::tools(); // Returns array of tool definitions
Error Handling
The SDK throws specific exception types for different error scenarios:
RefinderException (base)
├── AuthenticationException (HTTP 401)
├── SubscriptionException (HTTP 403)
├── ValidationException (HTTP 422)
├── RateLimitException (HTTP 429)
├── ToolException (HTTP 500/502)
└── ConnectionException (Network errors)
Exception Properties
| Exception | Extra Properties |
|---|---|
RefinderException |
errorCode, httpStatus |
ValidationException |
errors (array of field errors) |
RateLimitException |
limit, current |
ToolException |
executionId (UUID for debugging) |
Error Handling Example
use Refinder\LaravelSdk\Exceptions\AuthenticationException; use Refinder\LaravelSdk\Exceptions\RateLimitException; use Refinder\LaravelSdk\Exceptions\SubscriptionException; use Refinder\LaravelSdk\Exceptions\ToolException; use Refinder\LaravelSdk\Exceptions\ValidationException; use Refinder\LaravelSdk\Facades\Refinder; try { $result = Refinder::seo()->execute(['content' => $text]); return response()->json([ 'seo' => $result->output, 'tokens' => $result->usage->totalTokens, ]); } catch (ValidationException $e) { // Input validation failed (422) return response()->json(['error' => $e->errors], 422); } catch (RateLimitException $e) { // Quota exceeded (429) return response()->json([ 'error' => 'Rate limit reached', 'limit' => $e->limit, 'current' => $e->current, ], 429); } catch (SubscriptionException $e) { // Subscription issue (403) return response()->json(['error' => $e->getMessage()], 403); } catch (AuthenticationException $e) { // Invalid API key (401) Log::critical('Refinder API key is invalid!', ['code' => $e->errorCode]); return response()->json(['error' => 'Service unavailable'], 503); } catch (ToolException $e) { // AI processing failed (500/502) Log::error('Tool failed', ['execution_id' => $e->executionId]); return response()->json(['error' => 'Please retry'], 502); }
Error Codes Reference
| HTTP | Code | Description |
|---|---|---|
| 401 | MISSING_API_KEY |
No API key in request header |
| 401 | INVALID_API_KEY |
API key doesn't match any active key |
| 401 | API_KEY_EXPIRED |
API key has expired |
| 403 | PLATFORM_INACTIVE |
Platform is disabled |
| 403 | NO_ACTIVE_SUBSCRIPTION |
No active subscription |
| 403 | SUBSCRIPTION_EXPIRED |
Subscription has expired |
| 403 | TOOL_NOT_ALLOWED |
Plan doesn't include this tool |
| 404 | TOOL_NOT_FOUND |
Tool slug doesn't exist |
| 404 | EXECUTION_NOT_FOUND |
Execution UUID not found |
| 422 | VALIDATION_ERROR |
Input validation failed |
| 429 | DAILY_LIMIT_EXCEEDED |
Daily quota exceeded |
| 429 | MONTHLY_LIMIT_EXCEEDED |
Monthly quota exceeded |
| 500 | TOOL_ERROR |
Tool execution error |
| 502 | LLM_ERROR |
AI provider returned an error |
Events
When config('refinder.events') is true (default), the package dispatches Laravel events:
ToolExecuted
Dispatched after a successful tool execution:
use Refinder\LaravelSdk\Events\ToolExecuted; Event::listen(ToolExecuted::class, function (ToolExecuted $event) { Log::info("Refinder tool executed", [ 'tool' => $event->tool, // "seo" 'execution_id' => $event->executionId, 'tokens' => $event->tokensUsed, 'time_ms' => $event->executionTimeMs, ]); });
ToolExecutionFailed
Dispatched after a failed tool execution:
use Refinder\LaravelSdk\Events\ToolExecutionFailed; Event::listen(ToolExecutionFailed::class, function (ToolExecutionFailed $event) { Log::error("Refinder tool failed", [ 'tool' => $event->tool, 'error_code' => $event->errorCode, 'message' => $event->errorMessage, 'execution_id' => $event->executionId, ]); });
RateLimitApproaching
Dispatched when usage approaches the limit:
use Refinder\LaravelSdk\Events\RateLimitApproaching; Event::listen(RateLimitApproaching::class, function (RateLimitApproaching $event) { Log::warning("Approaching rate limit", [ 'type' => $event->limitType, // "daily" or "monthly" 'limit' => $event->limit, 'current' => $event->current, 'percentage' => $event->percentageUsed, ]); });
Caching
Enable response caching for identical tool inputs:
REFINDER_CACHE_ENABLED=true REFINDER_CACHE_TTL=60
- Uses Laravel's default cache driver
- Cache keys are generated from
prefix + tool_slug + md5(input) - Only successful executions are cached (never failures)
- TTL is in minutes
Rate Limiting & Quotas
The Refinder API enforces quotas based on your subscription plan:
| Limit | Reset Period |
|---|---|
| Daily | Midnight UTC |
| Monthly | 1st of month |
Checking Quota Usage
$usage = Refinder::usage(); $sub = Refinder::subscription(); $used = $usage->totalRequests; $limit = $sub->plan->maxRequestsPerMonth; $remaining = $limit - $used; $percentage = ($used / $limit) * 100; echo "Used {$used}/{$limit} ({$percentage}%) this month."; echo "{$remaining} requests remaining.";
Testing
The SDK provides a RefinderFake class for testing:
Basic Fake
use Refinder\LaravelSdk\Facades\Refinder; public function test_seo_analysis() { Refinder::fake(); // Your code calls the SDK as normal $result = Refinder::seo()->execute(['content' => 'Test content for SEO']); // Results come from the fake $this->assertEquals('completed', $result->status); $this->assertNotNull($result->output->metaTitle); $this->assertTrue($result->output->seoScore->isPassing()); // Assert the tool was called Refinder::assertToolExecuted('seo'); Refinder::assertToolExecutedCount('seo', 1); }
Custom Fake Responses
Refinder::fake(); Refinder::fakeToolExecution('seo', [ 'meta_title' => 'Custom Test Title', 'meta_description' => 'Custom test description.', 'keywords' => [ 'primary' => ['custom keyword'], 'secondary' => ['test'], 'long_tail' => ['custom long tail'], ], 'content_analysis' => [ 'readability_score' => 'excellent', 'word_count_assessment' => 'Perfect length.', 'content_quality' => 'high', 'key_topics_covered' => ['testing'], ], 'optimization_suggestions' => [], 'heading_structure' => [ 'suggested_h1' => 'Custom H1', 'suggested_h2s' => ['Custom H2'], 'suggested_h3s' => [], ], 'seo_score' => [ 'overall' => 95, 'content' => 90, 'keywords' => 95, 'structure' => 95, ], ]); $result = Refinder::seo()->execute(['content' => 'Any content']); $this->assertEquals('Custom Test Title', $result->output->metaTitle); $this->assertEquals(95, $result->output->seoScore->overall);
Assertions
Refinder::fake(); // Assert tool was executed Refinder::assertToolExecuted('seo'); // Assert exact count Refinder::assertToolExecutedCount('seo', 3); // Assert nothing was executed Refinder::assertNothingExecuted();
Real-World Examples
E-Commerce Product SEO
$product = Product::find(1); $result = Refinder::seo()->execute([ 'content' => $product->description, 'url' => route('products.show', $product), 'content_type' => 'product', 'brand_name' => $product->brand->name, 'industry' => $product->category->name, 'target_keywords' => $product->tags->pluck('name')->toArray(), ]); if ($result->isCompleted()) { $product->seoMeta()->updateOrCreate([], [ 'title' => $result->output->metaTitle, 'description' => $result->output->metaDescription, 'keywords' => $result->output->keywords->all(), 'h1' => $result->output->headingStructure->suggestedH1, 'score' => $result->output->seoScore->overall, 'analyzed_at' => now(), ]); }
Batch Processing with Queue
use Refinder\LaravelSdk\Facades\Refinder; use Refinder\LaravelSdk\Exceptions\RateLimitException; class AnalyzeArticleSeo implements ShouldQueue { public int $tries = 3; public int $backoff = 60; public function __construct(public Article $article) {} public function handle(): void { try { $result = Refinder::seo()->execute([ 'content' => $this->article->body, 'content_type' => 'article', 'language' => $this->article->locale, 'depth' => 'advanced', ]); $this->article->update([ 'seo_title' => $result->output->metaTitle, 'seo_description' => $result->output->metaDescription, 'seo_score' => $result->output->seoScore->overall, 'seo_analyzed_at' => now(), ]); } catch (RateLimitException $e) { $this->release(300); // retry in 5 minutes } } } // Dispatch for all unanalyzed articles Article::whereNull('seo_analyzed_at')->chunk(50, function ($articles) { foreach ($articles as $article) { AnalyzeArticleSeo::dispatch($article); } });
Admin Dashboard Integration
// Get platform info $platform = Refinder::me(); echo "Platform: {$platform->name} | Active: " . ($platform->isActive ? 'Yes' : 'No'); // Get subscription $sub = Refinder::subscription(); echo "Plan: {$sub->plan->name} | Monthly: {$sub->plan->maxRequestsPerMonth}"; // Get usage $usage = Refinder::usage(); echo "Requests: {$usage->totalRequests} | Tokens: {$usage->totalTokens}"; echo "Cost: \${$usage->totalCost}"; // Browse execution history $executions = Refinder::executions(perPage: 10); foreach ($executions->items as $exec) { echo "{$exec->id} | {$exec->tool} | {$exec->status} | {$exec->usage->totalTokens} tokens"; }
Package Structure
refinder-laravel-sdk/
├── src/
│ ├── RefinderServiceProvider.php # Auto-discovered service provider
│ ├── RefinderClient.php # Core HTTP client
│ ├── RefinderManager.php # Main manager (Facade target)
│ ├── Facades/
│ │ └── Refinder.php # Facade with fake() support
│ ├── Tools/
│ │ ├── BaseTool.php # Abstract base with caching/events
│ │ └── SeoTool.php # SEO tool wrapper
│ ├── DTOs/
│ │ ├── SeoInput.php # Input DTO
│ │ ├── SeoOutput.php # Full output DTO
│ │ ├── SeoKeywords.php # Keywords container
│ │ ├── SeoScore.php # Score with isPassing()
│ │ ├── SeoSuggestion.php # Single suggestion
│ │ ├── SeoContentAnalysis.php # Content analysis data
│ │ ├── SeoHeadingStructure.php # Heading suggestions
│ │ ├── ToolExecution.php # Execution result wrapper
│ │ ├── ExecutionUsage.php # Token/time usage
│ │ ├── ExecutionModel.php # AI model info
│ │ ├── PlatformInfo.php # Platform data
│ │ ├── SubscriptionInfo.php # Subscription details
│ │ ├── SubscriptionPlan.php # Plan limits/features
│ │ ├── UsageSummary.php # Usage aggregation
│ │ ├── UsageDay.php # Daily usage entry
│ │ └── PaginatedResult.php # Paginated list wrapper
│ ├── Exceptions/
│ │ ├── RefinderException.php # Base exception
│ │ ├── AuthenticationException.php # 401 errors
│ │ ├── SubscriptionException.php # 403 errors
│ │ ├── ValidationException.php # 422 errors
│ │ ├── RateLimitException.php # 429 errors
│ │ ├── ToolException.php # 500/502 errors
│ │ └── ConnectionException.php # Network errors
│ ├── Events/
│ │ ├── ToolExecuted.php # Success event
│ │ ├── ToolExecutionFailed.php # Failure event
│ │ └── RateLimitApproaching.php # Quota warning
│ ├── Contracts/
│ │ └── RefinderClientInterface.php # HTTP client interface
│ └── Testing/
│ ├── RefinderFake.php # Fake manager for tests
│ └── SeoToolFake.php # Fake SEO tool
├── config/
│ └── refinder.php # Configuration file
├── composer.json
├── README.md
├── LICENSE
└── CHANGELOG.md
Authentication
Every request to the Refinder API includes the platform's API key automatically:
X-API-Key: rfnd_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
| Property | Value |
|---|---|
| Prefix | rfnd_ |
| Total length | 53 characters |
| Format | rfnd_ + 48 alphanumeric characters |
The API key is read from config('refinder.api_key') and attached to every HTTP request by the RefinderClient.
Contributing
Contributions are welcome! Please see CONTRIBUTING.md for details.
Security
If you discover a security vulnerability, please send an email to security@refinder.ai instead of using the issue tracker.
License
The MIT License (MIT). Please see LICENSE for more information.
Built with care by the Refinder AI Tools team.