Refinder Laravel SDK

The official Laravel SDK for Refinder AI Tools — AI-powered SEO automation and content optimization for Laravel applications.

Requirements
PHP >= 8.2 · Laravel 11.x / 12.x
License
MIT — Open Source
What does the Refinder API do? It abstracts multiple LLM providers (OpenAI, DeepSeek, Alibaba Cloud Qwen) behind a unified interface, provides pluggable AI tools (starting with SEO), and manages subscriptions, usage quotas, and rate limiting.

Installation

Install the package via Composer:

Terminal
composer require refinder/laravel-sdk

The package auto-registers its service provider and facade via Laravel's package discovery. Publish the configuration file:

Terminal
php artisan vendor:publish --tag=refinder-config

Add your API key to the .env file:

.env
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_KEY is required. All other values have sensible defaults.

Quick Start

app/Http/Controllers/SeoController.php
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;
echo $result->output->metaDescription;
echo $result->output->seoScore->overall;  // 75 (0-100)

// Check if score is passing (>= 60)
if ($result->output->seoScore->isPassing()) {
    echo "SEO score is good!";
}

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');

Configuration

The full configuration file (config/refinder.php):

return [
    'api_key'       => env('REFINDER_API_KEY'),
    'base_url'      => env('REFINDER_BASE_URL', 'https://api.refinder.ai/api/v1'),
    'timeout'       => env('REFINDER_TIMEOUT', 120),
    'retries'       => env('REFINDER_RETRIES', 2),
    'retry_delay_ms' => env('REFINDER_RETRY_DELAY', 1000),
    'cache' => [
        'enabled' => env('REFINDER_CACHE_ENABLED', false),
        'ttl'     => env('REFINDER_CACHE_TTL', 60),
        'prefix'  => 'refinder_',
    ],
    'events'      => env('REFINDER_EVENTS', true),
    'log_channel' => env('REFINDER_LOG_CHANNEL', null),
];

Authentication

Every request includes the API key in the X-API-Key header automatically.

PropertyValue
Prefixrfnd_
Total length53 characters
Formatrfnd_ + 48 alphanumeric characters
StorageSHA-256 hashed server-side

SEO Tool

The SEO tool is the primary feature. It analyzes content and generates comprehensive SEO recommendations.

Input Parameters

ParameterTypeRequiredDefaultDescription
contentstringYesText content to analyze (min 10 chars)
urlstringNonullPage URL for additional context
content_typestringNo"page"article, product, service, page, blog
languagestringNo"en"Target language (en, ar, fr...)
depthstringNo"advanced"basic, advanced, technical
target_keywordsarrayNo[]Keywords to optimize around
brand_namestringNonullBrand name for titles/headings
industrystringNonullIndustry context

Depth Levels

LevelIncludes
basicMeta title, meta description, primary keywords
advancedEverything in basic + secondary/long-tail keywords, content analysis, heading suggestions, optimization suggestions, SEO scores
technicalEverything in advanced + schema markup, Open Graph tags, canonical URLs, content gap analysis

Using the SeoInput DTO

use Refinder\LaravelSdk\DTOs\SeoInput;

$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);

Working with SEO Output

$result = Refinder::seo()->execute(['content' => $text]);
$seo = $result->output;

// Meta tags
$seo->metaTitle;            // string (50-60 chars)
$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->contentQuality;      // 'high', 'medium', 'low'

// 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) {
    $suggestion->category;     // 'content', 'technical', 'structure'
    $suggestion->priority;     // 'high', 'medium', 'low'
    $suggestion->suggestion;   // "Add structured data..."
    $suggestion->isHighPriority(); // bool
}

// Heading Structure
$seo->headingStructure->suggestedH1;  // string
$seo->headingStructure->suggestedH2s; // array

// Execution metadata
$result->id;                       // UUID
$result->usage->totalTokens;       // 1276
$result->model->provider;         // 'alibaba'

API Reference — Platform Info

$platform = Refinder::me();

$platform->id;           // 1
$platform->name;         // "My Platform"
$platform->slug;         // "my-platform"
$platform->website;      // "https://example.com"
$platform->isActive;     // true

Subscription Details

$sub = Refinder::subscription();

$sub->plan->name;                // "Pro"
$sub->plan->maxRequestsPerMonth; // 1000
$sub->plan->maxRequestsPerDay;   // 100
$sub->plan->features;             // ['advanced_seo', ...]
$sub->isActive();                // true

Usage Statistics

$usage = Refinder::usage();
// Or with date range:
$usage = Refinder::usage('2026-01-01', '2026-01-31');

$usage->totalRequests; // 47
$usage->totalTokens;   // 62340
$usage->totalCost;     // 0.12468

foreach ($usage->daily as $day) {
    $day->date;           // "2026-02-08"
    $day->requestsCount;  // 12
    $day->tokensUsed;     // 15600
}

Execution History

$executions = Refinder::executions(perPage: 10, page: 1);

$executions->total;        // 47
$executions->hasMorePages(); // true

foreach ($executions->items as $exec) {
    $exec->id;     // UUID
    $exec->tool;   // "seo"
    $exec->status; // "completed"
}

// Get a specific execution
$exec = Refinder::execution('uuid-here');
if ($exec->isCompleted()) {
    echo $exec->output->metaTitle;
}

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)
Full 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;

try {
    $result = Refinder::seo()->execute(['content' => $text]);
} catch (ValidationException $e) {
    // 422 — Input validation failed
    return response()->json(['error' => $e->errors], 422);
} catch (RateLimitException $e) {
    // 429 — $e->limit, $e->current
} catch (SubscriptionException $e) {
    // 403 — Subscription issue
} catch (AuthenticationException $e) {
    // 401 — Invalid API key
} catch (ToolException $e) {
    // 500/502 — $e->executionId for debugging
}

Events

When config('refinder.events') is true, the package dispatches Laravel events:

use Refinder\LaravelSdk\Events\ToolExecuted;
use Refinder\LaravelSdk\Events\ToolExecutionFailed;
use Refinder\LaravelSdk\Events\RateLimitApproaching;

Event::listen(ToolExecuted::class, function (ToolExecuted $event) {
    Log::info("Tool executed", [
        'tool'         => $event->tool,
        'execution_id' => $event->executionId,
        'tokens'       => $event->tokensUsed,
    ]);
});

Caching

Enable response caching for identical tool inputs:

REFINDER_CACHE_ENABLED=true
REFINDER_CACHE_TTL=60
  • Uses Laravel's default cache driver
  • Cache keys: prefix + tool_slug + md5(input)
  • Only successful executions are cached (never failures)
  • TTL is in minutes

Rate Limiting & Quotas

Limit TypeReset PeriodFreeProEnterprise
DailyMidnight UTC10/day100/day1,000/day
Monthly1st of month50/month1,000/month10,000/month
$usage = Refinder::usage();
$sub   = Refinder::subscription();

$used      = $usage->totalRequests;
$limit     = $sub->plan->maxRequestsPerMonth;
$remaining = $limit - $used;

echo "Used {$used}/{$limit} this month. {$remaining} remaining.";

Testing

The SDK provides a RefinderFake class for testing without API calls:

use Refinder\LaravelSdk\Facades\Refinder;

public function test_seo_analysis()
{
    Refinder::fake();

    $result = Refinder::seo()->execute(['content' => 'Test content']);

    $this->assertEquals('completed', $result->status);
    $this->assertNotNull($result->output->metaTitle);
    $this->assertTrue($result->output->seoScore->isPassing());

    // Assertions
    Refinder::assertToolExecuted('seo');
    Refinder::assertToolExecutedCount('seo', 1);
}

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,
    'target_keywords' => $product->tags->pluck('name')->toArray(),
]);

if ($result->isCompleted()) {
    $product->seoMeta()->updateOrCreate([], [
        'title'       => $result->output->metaTitle,
        'description' => $result->output->metaDescription,
        'score'       => $result->output->seoScore->overall,
    ]);
}

Batch Processing with Queue

class AnalyzeArticleSeo implements ShouldQueue
{
    public int $tries = 3;
    public int $backoff = 60;

    public function handle(): void
    {
        try {
            $result = Refinder::seo()->execute([
                'content' => $this->article->body,
                'depth'   => 'advanced',
            ]);

            $this->article->update([
                'seo_score' => $result->output->seoScore->overall,
            ]);
        } catch (RateLimitException $e) {
            $this->release(300); // retry in 5 minutes
        }
    }
}

Error Code Reference

HTTPCodeDescription
401MISSING_API_KEYNo API key in request header
401INVALID_API_KEYAPI key doesn't match any active key
401API_KEY_EXPIREDAPI key has expired
403PLATFORM_INACTIVEPlatform is disabled
403NO_ACTIVE_SUBSCRIPTIONNo active subscription
403SUBSCRIPTION_EXPIREDSubscription has expired
403TOOL_NOT_ALLOWEDPlan doesn't include this tool
422VALIDATION_ERRORInput validation failed
429DAILY_LIMIT_EXCEEDEDDaily quota exceeded
429MONTHLY_LIMIT_EXCEEDEDMonthly quota exceeded
500TOOL_ERRORTool execution error
502LLM_ERRORAI provider returned an error