Laravel Integration

View as Markdown

This guide covers Laravel-specific configuration, HTTP calls, queues, and webhook handling. Request semantics are owned by Core Workflows.

Configuration

PUBLORA_API_KEY=sk_YOUR_API_KEY
PUBLORA_BASE_URL=https://api.publora.com/api/v1
PUBLORA_WEBHOOK_SECRET=your_webhook_secret
// config/services.php
'publora' => [
    'key' => env('PUBLORA_API_KEY'),
    'url' => env('PUBLORA_BASE_URL', 'https://api.publora.com/api/v1'),
    'webhook_secret' => env('PUBLORA_WEBHOOK_SECRET'),
],

Service wrapper

<?php
 
namespace App\Services;
 
use Illuminate\Support\Facades\Http;
 
final class Publora
{
    public function request(string $method, string $path, array $body = [], ?string $key = null): array
    {
        $request = Http::baseUrl(config('services.publora.url'))
            ->withHeaders(['x-publora-key' => config('services.publora.key')])
            ->timeout(30);
 
        if ($key) {
            $request = $request->withHeaders(['Idempotency-Key' => $key]);
        }
 
        return $request->send($method, $path, ['json' => $body])->throw()->json();
    }
}

Use bodies from Core Workflows. Do not add client-side platform ID regexes: IDs are opaque connection identifiers after the lowercase platform prefix.

Queue job

<?php
 
namespace App\Jobs;
 
use App\Services\Publora;
use Illuminate\Contracts\Queue\ShouldQueue;
 
final class SchedulePubloraPost implements ShouldQueue
{
    public function __construct(
        public string $content,
        public array $platforms,
        public string $requestId,
        public string $scheduledTime,
    ) {}
 
    public function handle(Publora $publora): void
    {
        $publora->request('POST', 'create-post', [
            'content' => $this->content,
            'platforms' => $this->platforms,
            'scheduledTime' => $this->scheduledTime,
        ], "laravel-{$this->requestId}");
    }
}
 
SchedulePubloraPost::dispatch(
    $content,
    $platforms,
    $requestId,
    now('UTC')->addMinutes(5)->toIso8601String(),
);

Compute scheduledTime before dispatching the job. Queue retries must reuse both the same timestamp and the same idempotency key; recomputing the timestamp changes the request body and returns 422 IDEMPOTENCY_KEY_CONFLICT.

Webhook route

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
 
Route::post('/webhooks/publora', function (Request $request) {
    $raw = $request->getContent();
    $expected = hash_hmac('sha256', $raw, config('services.publora.webhook_secret'));
    abort_unless(hash_equals($expected, $request->header('x-publora-signature', '')), 401);
    $envelope = json_decode($raw, true, flags: JSON_THROW_ON_ERROR);
    // Dispatch application work, then acknowledge quickly.
    return response()->noContent();
});

Exclude this route from CSRF protection as appropriate for your Laravel version, and verify the raw body before parsing. See Webhooks.