Official Python SDK for the in.bio URL shortener API: short links, QR codes, analytics, webhooks.
Project description
inbio — official Python SDK for INBIO (in.bio)
The official Python 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 Python.
- Free to start —
inbio.shorten()and the QR API need no account and no API key - Zero dependencies — pure standard library, full type hints, Python ≥ 3.9
- Complete — covers the entire INBIO REST API: links CRUD, generator pagination, bulk create, QR codes, analytics, webhook signature verification
Install
pip install inbio
Shorten a URL — no account, no API key
import inbio
print(inbio.shorten("https://example.com/very/long/url").short_url)
# https://in.bio/x7Kp2q
Keyless links are anonymous, rate-limited (5/min per IP), and deleted after
30 days unless claimed — the result's claim_url lets you keep one.
Authenticated quickstart
Create a token under Settings → API tokens (API access requires a Pro or Business plan), then:
from inbio import Inbio
client = Inbio("YOUR_TOKEN")
link = client.links.create("https://example.com/sale", slug="spring-sale")
print(link.short_url) # https://in.bio/spring-sale
print(link.total_clicks) # 0
List and iterate links
page = client.links.list(status="active", per_page=50)
print(page.total, page.current_page, page.has_next)
for link in page:
print(link.slug, link.destination_url)
# Auto-pagination: a generator that walks every page for you
for link in client.links.iterate(tag="marketing"):
print(link.short_url)
Create with options
link = client.links.create(
"https://example.com/launch",
slug="launch",
title="Product launch",
redirect_type=301,
folder_id=3,
tags=["marketing", "q3"],
expires_at="2026-12-31T23:59:59+00:00", # Pro+
fallback_url="https://example.com", # shown after expiry, Pro+
click_limit=10_000, # Pro+
password="s3cret", # Pro+
utm={"source": "newsletter", "medium": "email", "campaign": "launch"},
)
Update, enable, disable, delete
link = client.links.update(42, title="New title", tags=["archive"])
link = client.links.disable(42) # active -> disabled
link = 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
raises StateConflictError with the link's current status.
Bulk create (Business)
result = client.links.bulk_create([
{"destination_url": "https://example.com/a", "slug": "a1"},
{"destination_url": "https://example.com/b", "slug": "a1"}, # duplicate slug
])
for link in result.created:
print("created", link.slug)
for failure in result.failed:
print("row", failure.index, "failed:", failure.error)
QR code to a file
png = client.links.qr(42, format="png", size=512)
with open("spring-sale.png", "wb") as fh:
fh.write(png)
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-06-30")
print(stats.totals.clicks, stats.totals.uniques, stats.totals.bot_clicks)
for point in stats.series:
print(point["date"], point["clicks"])
for country in stats.countries: # top 10 by clicks
print(country["value"], country["clicks"])
# also: stats.devices, stats.browsers, stats.referrers, stats.range.from_/.to
Folders and tags
for folder in client.folders.list():
print(folder.id, folder.name, folder.links_count)
for tag in client.tags.list():
print(tag.name, tag.links_count)
Account usage
usage = client.account.usage()
print(usage.plan) # "pro"
print(usage.usage["links_created"]) # 120
print(usage.limits["links_per_month"]) # 2000
Webhook verification
Verify the X-Inbio-Signature header against the exact raw request body
(configure endpoints under Settings → Webhooks; Business plan). Example
Flask handler:
from flask import Flask, request, abort
from inbio import Inbio, SignatureVerificationError
app = Flask(__name__)
client = Inbio()
@app.post("/webhooks/inbio")
def inbio_webhook():
try:
event = client.webhooks.verify(
request.get_data(), # raw bytes, not parsed JSON
request.headers.get("X-Inbio-Signature"),
"whsec_YOUR_SIGNING_SECRET",
tolerance=300, # reject stale timestamps
)
except SignatureVerificationError:
abort(400)
if event["event"] == "link.clicked":
print("click on", event["data"]["slug"])
return "", 204
verify recomputes HMAC-SHA256(secret, "<t>.<raw body>"), compares in
constant time, and rejects timestamps older than tolerance seconds.
webhooks.construct_event(...) is an alias.
Error handling
Every SDK error derives from inbio.InbioError (with .message, .status,
.error_type, .body).
| Exception | HTTP | Extra attributes |
|---|---|---|
AuthenticationError |
401 | |
AccessError |
403 | error_type = plan / scope / account; required scope |
NotFoundError |
404 | |
StateConflictError |
409 | current link status |
ValidationError |
422 | errors — per-field messages |
EntitlementError |
422 (error.type=entitlement) |
plan feature/limit |
RateLimitError |
429 | retry_after seconds |
ServerError |
5xx | |
SignatureVerificationError |
— | webhook verification failed |
from inbio import Inbio, RateLimitError, ValidationError
try:
client.links.create("not-a-url")
except ValidationError as err:
print(err.errors) # {"destination_url": ["The destination url ..."]}
except RateLimitError as err:
print(err.retry_after) # seconds to wait
Retries and timeouts
client = Inbio(
"YOUR_TOKEN",
base_url="https://in.bio", # default
timeout=30, # seconds per request, default 30
max_retries=2, # default 2
)
Retries apply only to idempotent GET requests (connection errors and 5xx) and
to 429 responses that carry Retry-After, with exponential backoff capped at
10 seconds.
Authenticating via environment variable
# export INBIO_API_TOKEN=YOUR_TOKEN
from inbio import Inbio
client = Inbio() # picks up INBIO_API_TOKEN
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.
- Website: https://in.bio
- Documentation: https://docs.in.bio
- Free shorten API (no key): https://docs.in.bio/api/free-shorten
- Free QR code API (no key): https://docs.in.bio/api/free-qr
- MCP server for AI agents: https://docs.in.bio/api/mcp
- All SDKs (JavaScript, Python, PHP, Ruby, Go): https://docs.in.bio/sdks
License
MIT © InBio, Inc.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file inbio-0.1.0.tar.gz.
File metadata
- Download URL: inbio-0.1.0.tar.gz
- Upload date:
- Size: 19.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.6
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1d23313d6ed6c7eb9af1701c1fa963aaabc97854ee63c90e9c08d174bee9e679
|
|
| MD5 |
c7b310eb1c3d8f281363a5c8b6f0c341
|
|
| BLAKE2b-256 |
ddfe32ffcd94e2a9362dbdb92e9420ef5e4b23958c122c22c30f71d927e3ed67
|
File details
Details for the file inbio-0.1.0-py3-none-any.whl.
File metadata
- Download URL: inbio-0.1.0-py3-none-any.whl
- Upload date:
- Size: 16.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.6
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a6f30bb10f9bada79c3ce014ecdc500c8becf0e3a065cb4202e2902840ffab77
|
|
| MD5 |
3ffb0ea3848c167e529bdc1a652da4fe
|
|
| BLAKE2b-256 |
479c7e453119d709b2c58b9e0061016c7fab430469ca753784e0b4a4a5142c8b
|