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.