nulis.top

Custom CMS — Laravel

Contoh receiver webhook + upsert artikel.

Route

// routes/api.php
Route::post('/hooks/nulis', [NulisWebhookController::class, 'handle']);

Controller

namespace App\Http\Controllers;

use App\Models\Article;
use Illuminate\Http\Request;

class NulisWebhookController extends Controller
{
    public function handle(Request $request)
    {
        $secret = config('services.nulis.webhook_secret');
        $sig = $request->header('X-Nulis-Signature', '');
        $body = $request->getContent();
        $expected = 'sha256=' . hash_hmac('sha256', $body, $secret);
        if (!hash_equals($expected, $sig)) {
            abort(401);
        }

        $payload = $request->json()->all();
        $data = $payload['data'] ?? [];
        $uuid = $data['article_uuid'] ?? null;
        if (!$uuid) {
            return response()->json(['error' => 'missing uuid'], 422);
        }

        $seo = $data['seo_package']['seo'] ?? [];
        Article::updateOrCreate(
            ['external_uuid' => $uuid],
            [
                'title' => $data['title']['h1'] ?? $data['topic'],
                'slug' => $data['title']['slug'] ?? null,
                'body_html' => $data['content']['body_html'] ?? '',
                'meta_title' => $seo['meta_title'] ?? null,
                'meta_description' => $seo['meta_description'] ?? null,
                'focus_keyword' => $seo['focus_keyword'] ?? null,
            ]
        );

        return response()->json(['ok' => true]);
    }
}

Pull alternatif

$response = Http::withToken($apiKey)
    ->get("https://studio.nulis.top/api/v1/articles/{$uuid}");
$article = $response->json();

Gunakan article_uuid sebagai kunci idempotency.