turnley.dev

PHP and MySQL code for faucet operators

Tools & Calculators

ADS-005

A shortlink API compatible with what faucet scripts expect

Faucet software already knows how to talk to shortlink providers. Match the contract they expect and operators can point their existing config at you without writing anything.

Every faucet script on the market has a shortlink integration built in, and they all speak roughly the same dialect: a GET with an API token and a URL, returning JSON with a shortened link. An operator who has to write custom code to use your service will not use your service.

So do not invent a better interface. Match the one their software already sends, and the integration becomes pasting a token into a settings field.

The important design rule is that the publisher supplies a destination and nothing else. How many pages a visitor passes through, how long they wait, what gets shown along the way — those are yours to set globally. The moment a publisher can set the cycle length per link, they will set it to zero.

PHP
<?php
// api.php?api=TOKEN&url=https://dest&alias=optional&format=json
header('Content-Type: application/json');

$token = trim((string) ($_GET['api'] ?? ''));
$dest  = trim((string) ($_GET['url'] ?? ''));
$alias = preg_replace('~[^A-Za-z0-9\-_]~', '', (string) ($_GET['alias'] ?? '')) ?? '';

$member = $token === '' ? null : member_by_api_token($pdo, $token);
if (!$member) {
    echo json_encode(['status' => 'error', 'message' => 'invalid api token']);
    exit;
}
if (!filter_var($dest, FILTER_VALIDATE_URL) || !preg_match('~^https?://~i', $dest)) {
    echo json_encode(['status' => 'error', 'message' => 'invalid url']);
    exit;
}
if (is_own_host($dest)) {                 // never let links loop back into us
    echo json_encode(['status' => 'error', 'message' => 'invalid url']);
    exit;
}

$slug = $alias !== '' ? $alias : random_slug(7);
$slug = ensure_unique_slug($pdo, $slug);

$pdo->prepare('INSERT INTO links (member_id, site_id, slug, dest, created_at) VALUES (?, ?, ?, ?, NOW())')
    ->execute([$member['id'], (int) $member['first_verified_site_id'], $slug, $dest]);

$short = 'https://yournetwork.example/' . $slug;

// Some scripts ask for plain text. Give them exactly that, with no markup.
if (strtolower((string) ($_GET['format'] ?? 'json')) === 'text') {
    header('Content-Type: text/plain');
    echo $short;
    exit;
}

echo json_encode(['status' => 'success', 'shortenedUrl' => $short]);

Using it

Return errors in the same envelope as successes. A script that gets an HTML error page where it expected JSON will usually fall back to publishing the raw destination, and you lose the traffic without ever seeing an error.

Bind API-created links to the member's verified site so origin checks still apply to links your interface never saw.

What bites people

Do not reinvent the response shape. Match the field names the popular providers use or existing integrations will not parse it.

Reject links pointing back at your own domain. A shortlink that lands on your own gateway makes an infinite loop that looks like a traffic spike.

Rate limit per token and per address. An API endpoint that mints rows on GET is the easiest thing on your site to abuse.

This one touches real money. Point it at a throwaway wallet and watch a full cycle before you trust it with a live balance.

Also in Ads, Traffic and Offerwalls