Bulk URL Shortening with the API: Automate Link Creation
When you need hundreds of short links instead of one, clicking through a UI stops being an option. Here's how to automate the job with code.
When You Need Bulk Shortening
A single short link is a copy-paste job. A product catalog with a thousand SKUs, a batch of tracked links for every influencer in an affiliate program, or a CI pipeline that needs a fresh preview link per pull request is a different problem entirely — one that only automation solves cleanly.
The TinyUR API exposes a single, focused endpoint — POST /api/shorten — for creating a short link from a URL and an optional custom alias. There's no separate "bulk" endpoint, and that's fine: a plain loop with sensible pacing gets you the same result reliably. Full parameter details live on the API docs page.
The Core Request
Every call takes a JSON body with a required url and an optional customAlias (3–50 characters, letters, numbers, hyphens, and underscores only):
curl -X POST https://tinyur.in/api/shorten \
-H "Content-Type: application/json" \
-d '{
"url": "https://example.com/products/wireless-headphones",
"customAlias": "headphones-launch"
}'A successful response returns the original URL, the short code, and the full short URL. If the alias is already taken by a different destination, the API returns a 400 with an error message instead of silently overwriting it.
Scripting a Batch from a CSV
The most common real-world case is a spreadsheet of destination URLs — a product feed, a list of campaign landing pages — that needs a short link generated per row. A small Node.js script handles this cleanly:
import { parse } from "csv-parse/sync";
import { readFileSync, writeFileSync } from "fs";
const rows = parse(readFileSync("links.csv"), { columns: true });
const results = [];
for (const row of rows) {
const res = await fetch("https://tinyur.in/api/shorten", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
url: row.destination,
customAlias: row.alias || undefined,
}),
});
const data = await res.json();
if (!res.ok) {
console.error(`Failed for ${row.destination}: ${data.error}`);
continue;
}
results.push({ ...row, shortUrl: data.shortUrl });
// Small delay between requests — considerate of the service,
// and avoids tripping rate limits on large batches.
await new Promise((r) => setTimeout(r, 150));
}
writeFileSync("links-with-short-urls.csv", toCsv(results));Two details matter more than the happy path here: checking res.ok before trusting the response, and pacing requests instead of firing them all at once. Both keep a large batch from silently losing rows or getting throttled partway through.
Patterns Worth Following
🐢 Throttle, Don't Flood
Sending thousands of requests in a tight loop with no delay looks identical to abusive traffic from the server's point of view. Space requests out — even a modest delay between calls — and batch large jobs into chunks with pauses between them.
🔁 Make Retries Idempotent
If a request fails on a network blip, retrying with the same customAlias is safe — a duplicate alias with the same destination is handled gracefully. Retrying with a freshly generated alias on every attempt, by contrast, risks littering your account with abandoned partial links.
📝 Log the Mapping, Not Just the Result
Keep a record of which source row produced which short URL — a CSV with an appended column, as in the script above, or a simple database table. Without it, regenerating or auditing a batch months later means starting from scratch.
🏷️ Derive Aliases from Structured Data
When source rows have a natural identifier — a SKU, a campaign name, an influencer handle — build the alias from it (sku-4471, creator-jdoe-q3) instead of leaving it blank. See our URL shortening best practices guide for more on naming conventions that stay readable at scale.
✅ Validate Before You Submit
Filter out blank, malformed, or duplicate URLs client-side before the batch runs. It's cheaper to catch a bad row in a local check than to debug why a request came back with an error deep into a thousand-row job.
Automating Inside a Pipeline
The same request shape works from a CI job, a serverless function, or a CMS webhook — anywhere you can make an HTTP call. A common pattern is generating a short, shareable preview link automatically whenever new content is published, so the link is ready the moment the announcement goes out instead of being created by hand afterward.
Key Takeaways
- ▹A single, well-scripted loop over the shorten endpoint handles bulk creation without needing a dedicated bulk API
- ▹Always check the response status — a failed request returns a JSON error, not an exception
- ▹Throttle requests and chunk large batches instead of firing them all at once
- ▹Derive custom aliases from structured source data so links stay readable and auditable
- ▹Keep a persistent log mapping source rows to generated short URLs