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.
| Code | Means | What to do |
|---|---|---|
validation_error | The row did not parse — bad URL, alias too long, unknown key | Fix the cell and resend that row |
conflict | The alias is taken, or repeats an earlier row in this batch | Choose another alias |
upgrade_required | The row fell past your remaining monthly quota | Send it next month, or raise the plan |
internal | Something on our side | Resend the row; tell us if it repeats |
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
Get the list into one column
One URL per line, no headers, no numbering. Anything else is a formatting bug waiting to happen.
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.
Download the CSV
You get the short link next to each original, ready to paste back into the sheet as a column.
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 toolWhich 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.
Keep going
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.