Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

inbio/inbio — official PHP SDK for INBIO (in.bio)

The official PHP SDK for INBIO, the premium URL shortener with click analytics and customizable QR codes. Shorten links, generate styled QR codes, read analytics, and manage folders and tags from PHP.

  • Free to startInbio::shorten() and the QR API need no account and no API key
  • Zero Composer dependencies — PHP ≥ 8.1 with ext-curl; readonly typed models, named arguments
  • Complete — covers the entire INBIO REST API: links CRUD, generator pagination, bulk create, QR codes, analytics, webhook signature verification

Install

composer require inbio/inbio

Shorten a URL in three lines

No account, no API key:

$result = \Inbio\Inbio::shorten('https://example.com/some/very/long/url');
echo $result->shortUrl; // https://in.bio/abc123

shorten() returns a ShortenResult with shortUrl, slug, qrUrl, previewUrl, claimUrl and expires. Keyless links are anonymous and deleted after 30 days unless claimed via claimUrl.

Authenticated quickstart

Create a token under Settings → API tokens (API access is a Pro/Business feature), then:

use Inbio\Client;

$client = new Client(token: 'YOUR_API_TOKEN');

$link = $client->links->create('https://example.com/sale', slug: 'spring-sale');
echo $link->shortUrl; // https://in.bio/spring-sale

Omit the token to fall back to the INBIO_API_TOKEN environment variable:

$client = new Client(); // reads INBIO_API_TOKEN

Links

List and iterate

// One page at a time
$page = $client->links->list(status: 'active', perPage: 50);
foreach ($page->data as $link) {
    echo "{$link->slug}: {$link->totalClicks} clicks\n";
}
echo $page->total;       // total matching links
echo $page->currentPage; // current page number
var_dump($page->hasNext); // is there a next page?

// Or let the SDK paginate for you — iterate() is a Generator
foreach ($client->links->iterate(tag: 'marketing') as $link) {
    echo $link->shortUrl, "\n";
}

listAll() is an alias of iterate(). Filters: search, folderId, tag, status, perPage.

Create with options

$link = $client->links->create(
    'https://example.com/sale',
    slug: 'spring-sale',          // omit for a random slug
    title: 'Spring sale',
    redirectType: 301,            // 301, 302 (default) or 307
    folderId: 3,
    tags: ['marketing', 'q3'],    // created on the fly
    expiresAt: '2026-09-01T00:00:00+00:00', // Pro+
    fallbackUrl: 'https://example.com',     // shown after expiry; Pro+
    clickLimit: 10000,            // Pro+
    password: 'hunter2',          // Pro+
    utm: ['source' => 'newsletter', 'campaign' => 'spring'],
);

Update, enable, disable, delete

$client->links->update(42, title: 'New title', tags: ['sale']);
// or with an array: $client->links->update(42, ['title' => 'New title']);

$client->links->disable(42); // active -> disabled
$client->links->enable(42);  // disabled -> active
$client->links->delete(42);  // soft-delete, stops redirecting

Enable/disable only toggle between active and disabled; any other status throws a StateConflictException carrying the current status.

Bulk create (Business)

$result = $client->links->bulkCreate([
    ['destination_url' => 'https://example.com/1', 'slug' => 'promo-1'],
    ['destination_url' => 'https://example.com/2', 'slug' => 'promo-2'],
]);

foreach ($result->created as $link) { /* Link objects */ }
foreach ($result->failed as $row) {
    echo "row {$row['index']} failed: {$row['error']}\n";
}

Rows fail independently — up to 100 per call.

QR code straight to a file

file_put_contents('spring-sale.png', $client->links->qr(42, size: 512));
file_put_contents('spring-sale.svg', $client->links->qr(42, format: 'svg'));

The QR encodes the short URL, so editing the destination never invalidates printed codes.

Analytics

$stats = $client->links->analytics(42, from: '2026-06-01', to: '2026-07-01');

echo $stats->totals['clicks'];   // 1240
echo $stats->totals['uniques'];  // 981
foreach ($stats->series as $day) {
    echo "{$day['date']}: {$day['clicks']}\n";
}
// Also: $stats->countries, ->devices, ->browsers, ->referrers (top 10 by clicks)

Folders and tags

foreach ($client->folders->list() as $folder) {
    echo "{$folder->name} ({$folder->linksCount} links)\n";
}
foreach ($client->tags->list() as $tag) {
    echo "{$tag->name}\n";
}

Account usage

$usage = $client->account->usage();
echo $usage->plan;                          // "pro"
echo $usage->usage['links_created'];        // 120
echo $usage->limits['links_per_month'];     // 2000

Webhook verification

in.bio signs every webhook delivery with X-Inbio-Signature: t=<unix>,v1=<hex>. Verify with the raw request body — do not decode and re-encode it first:

use Inbio\Exception\SignatureVerificationException;
use Inbio\Resources\Webhooks;

// In your HTTP handler (plain PHP shown; the same works in any framework):
$payload = file_get_contents('php://input');
$signature = $_SERVER['HTTP_X_INBIO_SIGNATURE'] ?? '';

try {
    $event = (new Webhooks())->verify($payload, $signature, $endpointSecret);
    // or: $client->webhooks->verify(...)
} catch (SignatureVerificationException $e) {
    http_response_code(400);
    exit;
}

match ($event->event) {
    'link.created' => handleCreated($event->data),
    'link.click_limit_reached' => notifyTeam($event->data),
    default => null,
};

http_response_code(200);

Verification uses hash_hmac('sha256', ...) with a constant-time comparison and rejects timestamps older than 5 minutes (configurable via the tolerance parameter) to prevent replay attacks. constructEvent() is an alias of verify().

Error handling

All exceptions extend Inbio\Exception\InbioException, which exposes status, errorType and responseBody:

use Inbio\Exception\RateLimitException;
use Inbio\Exception\ValidationException;

try {
    $client->links->create('https://example.com', slug: 'taken');
} catch (ValidationException $e) {
    print_r($e->errors); // ['slug' => ['This slug is already taken.']]
} catch (RateLimitException $e) {
    sleep($e->retryAfter ?? 60);
}
Exception (in Inbio\Exception) HTTP Extra fields
AuthenticationException 401
AccessException 403 errorType = plan/scope/account, required scope
NotFoundException 404
StateConflictException 409 current status
ValidationException 422 errors map (field => messages)
EntitlementException 422 (error.type=entitlement) plan feature/limit
RateLimitException 429 retryAfter seconds
ServerException 5xx
SignatureVerificationException webhook verification failure

Retries and timeouts

$client = new Client(
    token: 'YOUR_API_TOKEN',
    baseUrl: 'https://in.bio', // default
    timeout: 30.0,             // seconds, default 30
    maxRetries: 2,             // default 2
);

The client retries only idempotent GET requests (on network errors and 5xx) and 429 responses that carry a Retry-After header, with exponential backoff capped at 10 seconds. Non-idempotent requests are never retried automatically.

Environment-variable auth

Set INBIO_API_TOKEN and construct the client without arguments — handy for CI and twelve-factor apps:

export INBIO_API_TOKEN=inbio_pat_...
$client = new \Inbio\Client();

Docs

Full API reference: https://docs.in.bio

About INBIO

INBIO (in.bio) is a URL shortener and link-management platform: short links with custom slugs, real-time click analytics (countries, devices, browsers, referrers — bots filtered out), a QR code studio with dot styles, marker shapes and colors, folders, tags, UTM tools, and a REST API with webhooks. Free plan included.

License

MIT © InBio, Inc.

About

Official PHP SDK for INBIO (in.bio) — URL shortener, QR codes, click analytics. Zero dependencies, free keyless endpoints.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages