Blog

Bulk URL shortening: 1,000 links in one request, without a mess

How to shorten a spreadsheet of links properly — the row limit, what happens to a bad row, why aliases collide inside a batch, and how to get the results back into your sheet.

By Wasim Idrishi · Updated · 4 min read

A thousand product URLs, one per SKU, each needing a short link for a printed catalogue. Done by hand that is a fortnight. Done badly with a script that fires a thousand parallel requests, it is a rate-limit wall and a half-finished spreadsheet you cannot tell apart from a finished one.

The shape of the endpoint

POST /api/v1/links/bulk takes an array of rows and an optional domain. A row carries only what varies: the URL, and optionally an alias, a title and tags. Everything a batch shares — the host — is set once on the request.

Up to 1,000 rows per call. The rows are validated with exactly the same schema that a single link goes through, then each valid row is created through exactly the same code path as a single link: safety check on the destination, alias rules, quota accounting, audit entry, event emitted. There is no fast path that skips checks because the request happened to be a batch. That is the point of the design, and it is the reason a bulk import cannot produce a link you could not have made one at a time.

The response is a ledger, not a status

Every row comes back with its index and one of two shapes: the created link, or an error with a machine code and a human sentence.

CodeMeansWhat to do
validation_errorThe row did not parse — bad URL, alias too long, unknown keyFix the cell and resend that row
conflictThe alias is taken, or repeats an earlier row in this batchChoose another alias
upgrade_requiredThe row fell past your remaining monthly quotaSend it next month, or raise the plan
internalSomething on our sideResend the row; tell us if it repeats
What a failed row tells you

Because the index is preserved, you can join the results back onto the spreadsheet you sent without matching on URL strings — which matters, because two rows in a real catalogue often share a URL.

Four things that bite

Aliases colliding inside one batch. Two rows asking for spring-sale is a common copy-paste result. The import detects the repeat before writing anything, keeps the first and refuses the second with a message naming the earlier row number. Without that check the two inserts would race the unique index and you would get a random winner.

Quota discovered halfway. The batch counts the links you have already created this month, works out what is left, and refuses the overflow rows up front rather than creating 300 and failing on the 301st. You get a clean line between what exists and what does not.

Concurrency. Rows are created a few at a time, not all at once. A batch of 1,000 takes as long as it takes; if you are scripting this, set a generous client timeout rather than retrying, because a retry on a partially applied batch will collide with the aliases it already created.

Destinations that are wrong in bulk. A spreadsheet's worth of URLs assembled by formula tends to contain the same mistake a thousand times — a staging host, a missing locale segment, a trailing quote. Check twenty rows by hand before you send a thousand.

Doing it without writing code

  1. Get the list into one column

    One URL per line, no headers, no numbering. Anything else is a formatting bug waiting to happen.

  2. Paste up to 100 into the bulk tool

    It needs a free account, for the same reason anonymous shortening is rate limited: unmetered bulk creation is what abuse looks like. Duplicate lines are dropped before anything is created.

  3. Download the CSV

    You get the short link next to each original, ready to paste back into the sheet as a column.

  4. Spot-check five, then print

    Open five short links at random from the finished CSV. Five is enough to catch a whole-column error and quick enough that you will actually do it.

Bulk URL Shortener

Open the full tool

Which plan

The bulk endpoint is a Business feature. The free tool on this site is a different mechanism with the same shape: it deduplicates your pasted lines, caps them at 100, and sends them one at a time to the ordinary create endpoint — so a free account is enough, and each link counts against your normal monthly allowance. That is the right size for a campaign. The batch endpoint is the right size for a catalogue, a store feed, or anything a nightly job produces.

Both create ordinary branded links: editable destinations, per-link analytics, a QR at .qr or .svg, and no expiry on a paid plan. Nothing about a link is different because it arrived in a batch.

Questions people ask

How many links can I create at once?

Up to 1,000 rows in a single API request to the bulk endpoint. The free tool on this site caps at 100 per run and sends them one at a time to the ordinary create endpoint, which is why it works on a free account. For more than 1,000, send several requests.

Does one bad row fail the whole batch?

No. Every row is validated independently and the response reports each one by its index with either the created link or the reason it failed. A malformed URL in row 40 does not touch rows 1 to 39.

What happens if two rows ask for the same alias?

The first row wins and the later one is refused with a message naming the row it collided with. That check runs before anything is written, so two rows never race each other against the uniqueness index.

What if the batch is bigger than my monthly quota?

Rows beyond the remaining quota are refused up front with an upgrade_required code and a body saying the limit, how much you have used and which plan you are on. The rows that fit are still created.

Can I bulk-import to my own domain?

Yes. Set the batch domain once on the request rather than repeating it per row, and every link in the batch is created on that host.

Try it with your own link

Paste a long link and get a 10-character gc.mw link with a QR code. No account needed for 30 days; free forever with one.