Skip to main content
Back to Blogs
URL Shortening~10 min read

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