Guides / PHP

PHP

Call the Lagoon API from PHP using cURL. Covers search, artist lookup, pagination, authentication, and error handling. No external dependencies.

Prerequisites

PHP 8.0 or later with the cURL extension (enabled by default on most installations).

Search by tag

Find posts by an exact tag name using the tag parameter.

$url = "https://lagoon.io/api/v1/search?" . http_build_query([ "tag" => "blue_hair", "limit" => 10, ]); $ch = curl_init($url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $response = curl_exec($ch); curl_close($ch); $data = json_decode($response, true); if ($data["ok"]) { foreach ($data["results"] as $post) { echo "{$post['title']} by {$post['artist_handle']}\n"; echo " Platform: {$post['platform_name']}\n"; echo " Tags: " . implode(", ", array_slice($post["tags"], 0, 5)) . "\n\n"; } }

Each post in results includes id, source_url, title, posted_at, platform, platform_name, artist_handle, artist_name, deleted, and tags.

Natural language search

Pass freeform text to the nl parameter. The API extracts platform, artist, date range, tags, and sort order from your query. The response includes a filters key showing what was parsed.

$url = "https://lagoon.io/api/v1/search?" . http_build_query([ "nl" => "solo girl on pixiv from 2025", ]); $ch = curl_init($url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $response = curl_exec($ch); curl_close($ch); $data = json_decode($response, true); // See what the parser extracted print_r($data["filters"] ?? []); // ['platform' => 'pixiv', 'from' => '2025-01-01', 'to' => '2025-12-31', 'tags' => ['solo'], ...] foreach ($data["results"] as $post) { echo $post["title"] . "\n"; }

Look up an artist

Query a handle to get all linked accounts across platforms.

$ch = curl_init("https://lagoon.io/api/v1/artist?" . http_build_query([ "handle" => "hews__", ])); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $response = curl_exec($ch); curl_close($ch); $data = json_decode($response, true); if ($data["ok"]) { $artist = $data["artist"]; echo "{$artist['display_name']} ({$artist['post_count']} posts)\n"; foreach ($artist["platforms"] as $p) { echo " {$p['platform_name']}: {$p['handle']}\n"; if ($p["profile_url"]) { echo " {$p['profile_url']}\n"; } } }

Authenticate with an API key

Unauthenticated requests are rate-limited to 30 per minute. To use a higher-limit tier, pass your key in the X-API-Key header.

$apiKey = "lg_your_key_here"; $ch = curl_init("https://lagoon.io/api/v1/search?" . http_build_query([ "tag" => "blue_hair", "limit" => 20, ])); curl_setopt_array($ch, [ CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => ["X-API-Key: {$apiKey}"], ]); $response = curl_exec($ch); curl_close($ch); $data = json_decode($response, true);

Paginate through results

Use limit and offset to page through results. When the response count is less than your limit, you have reached the last page.

function search_all(array $params): array { $results = []; $offset = 0; $limit = $params["limit"] ?? 50; while (true) { $params["offset"] = $offset; $url = "https://lagoon.io/api/v1/search?" . http_build_query($params); $ch = curl_init($url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $response = curl_exec($ch); curl_close($ch); $data = json_decode($response, true); if (!$data["ok"]) break; array_push($results, ...$data["results"]); if ($data["count"] < $limit) break; $offset += $limit; } return $results; } // Fetch all blue_hair posts from Bluesky $posts = search_all([ "tag" => "blue_hair", "platform" => "bluesky", "limit" => 100, ]); echo "Total: " . count($posts) . " posts\n";

Handle errors

The API returns "ok": false with an error message on failure. Check the HTTP status code for specific error types.

function lagoon_get(string $endpoint, array $params = [], string $apiKey = ""): array { $url = "https://lagoon.io/api/v1/" . $endpoint . "?" . http_build_query($params); $headers = []; if ($apiKey !== "") { $headers[] = "X-API-Key: {$apiKey}"; } $ch = curl_init($url); curl_setopt_array($ch, [ CURLOPT_RETURNTRANSFER => true, CURLOPT_TIMEOUT => 10, CURLOPT_HTTPHEADER => $headers, ]); $body = curl_exec($ch); $status = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); if ($status === 429) { throw new RuntimeException("Rate limited. Try again later."); } if ($status === 402) { throw new RuntimeException("Insufficient balance."); } if ($status === 401) { throw new RuntimeException("Invalid or expired API key."); } $data = json_decode($body, true); if (!$data["ok"]) { throw new RuntimeException($data["error"] ?? "Unknown error"); } return $data; } // Usage try { $data = lagoon_get("search", ["tag" => "blue_hair", "limit" => 10]); foreach ($data["results"] as $post) { echo $post["title"] . "\n"; } } catch (RuntimeException $e) { echo "API error: {$e->getMessage()}\n"; }

Full example

A standalone CLI script that looks up an artist and prints their recent posts.

#!/usr/bin/env php <?php // search.php - run with: php search.php hews__ $handle = $argv[1] ?? null; if (!$handle) { fwrite(STDERR, "Usage: php search.php <artist_handle>\n"); exit(1); } $base = "https://lagoon.io/api/v1"; function api_get(string $url): array { $ch = curl_init($url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $body = curl_exec($ch); curl_close($ch); return json_decode($body, true); } // Step 1: Look up the artist $artist_data = api_get("{$base}/artist?" . http_build_query(["handle" => $handle])); if (!$artist_data["ok"]) { fwrite(STDERR, "Error: " . ($artist_data["error"] ?? "Not found") . "\n"); exit(1); } $artist = $artist_data["artist"]; echo "{$artist['display_name']} - {$artist['post_count']} indexed posts\n"; foreach ($artist["platforms"] as $p) { echo " {$p['platform_name']}: {$p['handle']}\n"; } echo "\n"; // Step 2: Get their recent posts $search_data = api_get("{$base}/search?" . http_build_query([ "artist" => $handle, "limit" => 5, ])); if ($search_data["ok"]) { foreach ($search_data["results"] as $post) { echo $post["title"] ?? "Post #{$post['id']}"; echo "\n"; echo " {$post['platform_name']} | " . substr($post["posted_at"], 0, 10) . "\n"; $tags = array_filter($post["tags"], fn($t) => !str_starts_with($t, "rating:")); echo " Tags: " . implode(", ", array_slice($tags, 0, 8)) . "\n"; if ($post["source_url"]) { echo " {$post['source_url']}\n"; } echo "\n"; } }

Next steps