Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

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 startinbio.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.

License

MIT © InBio, Inc.

About

Official Python 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