URL Shortener API in PHP: Complete Integration Guide
Integrate the URLW URL shortener API in PHP. Complete code examples using curl, error handling, and best practices for Symfony and Laravel applications.
Integrating URL shortening into a PHP application is straightforward with the URLW REST API. Whether you are building a Symfony application, a Laravel project, or plain PHP, this guide provides production-ready code you can adapt directly. We cover authentication, creating links, retrieving statistics, and proper error handling.
Prerequisites
You need a URLW account with API access enabled (available on Starter plans and above). Generate your API token at Settings → API Keys in your URLW dashboard. Store it as an environment variable — never hardcode tokens in your source code.
# .env
URLW_API_TOKEN=your_api_token_here
URLW_API_BASE=https://urlw.fr/api/v1
A Minimal PHP Client Class
The following class wraps the URLW API with proper error handling and can be dropped into any PHP 8+ project:
<?php
class UrlwClient
{
private string $baseUrl;
private string $token;
public function __construct(string $token, string $baseUrl = 'https://urlw.fr/api/v1')
{
$this->token = $token;
$this->baseUrl = rtrim($baseUrl, '/');
}
private function request(string $method, string $endpoint, array $body = []): array
{
$ch = curl_init();
$url = $this->baseUrl . '/' . ltrim($endpoint, '/');
$headers = [
'Authorization: Bearer ' . $this->token,
'Content-Type: application/json',
'Accept: application/json',
];
curl_setopt_array($ch, [
CURLOPT_URL => $url,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => $headers,
CURLOPT_TIMEOUT => 10,
]);
if ($method === 'POST') {
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($body));
} elseif ($method === 'PATCH') {
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PATCH');
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($body));
} elseif ($method === 'DELETE') {
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'DELETE');
}
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if (curl_errno($ch)) {
throw new RuntimeException('cURL error: ' . curl_error($ch));
}
curl_close($ch);
$data = json_decode($response, true);
if ($httpCode >= 400) {
$message = $data['message'] ?? 'Unknown API error';
$code = $data['code'] ?? 'api_error';
throw new RuntimeException("URLW API error [{$code}]: {$message}", $httpCode);
}
return $data ?? [];
}
public function createLink(string $url, ?string $slug = null, ?string $domain = null): array
{
$payload = ['url' => $url];
if ($slug !== null) $payload['slug'] = $slug;
if ($domain !== null) $payload['domain'] = $domain;
return $this->request('POST', '/links', $payload);
}
public function getLink(string $id): array
{
return $this->request('GET', '/links/' . $id);
}
public function getLinkStats(string $id): array
{
return $this->request('GET', '/links/' . $id . '/stats');
}
public function listLinks(int $page = 1, int $perPage = 50): array
{
return $this->request('GET', "/links?page={$page}&per_page={$perPage}");
}
public function deleteLink(string $id): void
{
$this->request('DELETE', '/links/' . $id);
}
}
Using the Client in Practice
<?php
require_once 'UrlwClient.php';
$client = new UrlwClient(getenv('URLW_API_TOKEN'));
try {
// Create a short link with a custom slug
$link = $client->createLink(
url: 'https://myapp.com/blog/2024-feature-update',
slug: 'blog-update-june'
);
echo "Short URL: " . $link['short_url'] . PHP_EOL;
echo "Link ID: " . $link['id'] . PHP_EOL;
// Retrieve statistics
$stats = $client->getLinkStats($link['id']);
echo "Total clicks: " . $stats['total_clicks'] . PHP_EOL;
} catch (RuntimeException $e) {
// Log the error — do not expose API errors to end users
error_log('URLW error: ' . $e->getMessage());
// Handle gracefully in your application
}
Symfony Service Integration
In a Symfony application, register the client as a service and inject your API token via the environment:
# config/services.yaml
services:
App\Service\UrlwClient:
arguments:
$token: '%env(URLW_API_TOKEN)%'
Then typehint UrlwClient in your controllers or services and Symfony's dependency injection container will handle instantiation automatically.
Rate Limiting and Retries
For bulk operations, implement a simple retry with exponential backoff when you receive a 429 HTTP status code. Inspect the X-RateLimit-Reset header to know exactly when to resume requests rather than guessing with fixed delays.
Explore the Full API
The complete API reference is available at /en/docs/api. Create your account at /en/register and review available plans at /en/#pricing.
Try URLW for free
50 short links, REST API included, no credit card required.