Plain-Ruby models, keyword arguments, lazy enumerators, zero runtime dependencies. Ruby ≥ 3.0.
gem install inbioShorten a URL (no account)
require "inbio"
link = Inbio.shorten("https://example.com/very/long/url")
puts link.short_url # https://in.bio/a8K2pAuthenticated client
Pass a token or set INBIO_API_TOKEN in the environment:
client = Inbio::Client.new # reads INBIO_API_TOKEN
created = client.links.create(
"https://example.com/sale",
slug: "spring-sale",
tags: ["marketing"],
utm: { source: "newsletter", medium: "email" }
)Everything else
# List with filters, or iterate every page automatically (lazy Enumerator)
page = client.links.list(status: "active", per_page: 50)
client.links.iterate(tag: "marketing").each do |link|
puts "#{link.slug} #{link.total_clicks}"
end
# Update, toggle, delete
client.links.update(42, title: "Renamed")
client.links.disable(42)
client.links.enable(42)
client.links.delete(42)
# QR code bytes → file
File.binwrite("qr.png", client.links.qr(42, format: "png", size: 1024))
# Analytics, folders, tags, usage
stats = client.links.analytics(42, from: "2026-06-01")
folders = client.folders.list
tags = client.tags.list
usage = client.account.usageErrors
begin
client.links.create(url)
rescue Inbio::ValidationError => e
p e.errors # per-field messages
rescue Inbio::RateLimitError => e
p e.retry_after # seconds
endInbio::AuthenticationError (401), Inbio::AccessError (403, plan or scope),
Inbio::NotFoundError, Inbio::ValidationError, Inbio::EntitlementError,
Inbio::StateConflictError (409), Inbio::RateLimitError (429),
Inbio::ServerError — all inherit Inbio::Error. GETs and Retry-After
429s are retried automatically with backoff.
Webhooks
# e.g. in a Rails controller
event = Inbio::Webhooks.verify(
request.raw_post,
request.headers["X-Inbio-Signature"],
secret
)
if event["event"] == "link.clicked"
# ...
endSignatures are checked with a constant-time comparison and a 5-minute replay-protection window. See Webhooks for the payload format.