Bulk create
Create up to 10,000 links in one request, and read the per-row results.
Importing a spreadsheet, generating a link per customer, migrating from another shortener: all of it is one request rather than thousands. That matters for more than tidiness: the batch costs a single request against your per-minute budget, so an import that would take hours one link at a time takes seconds.
Create links in bulk
/api/v1/links/bulk
Up to 10,000 links in a single request, with a result row for each one.
| Field | Type | Required | Description |
|---|---|---|---|
links |
array | required | The links to create, at most 10,000. Each entry takes url, and optionally alias, expiresOn and password: the same fields as a single create. |
domain |
string | optional | A custom domain of yours, applied to every link in the batch. |
expiresOn |
integer | optional | A default expiry in unix seconds for the whole batch. An expiry on an individual link wins over it. |
curl -X POST "https://urlicer.com/api/v1/links/bulk" \
-H "Authorization: Bearer url_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"links": [
{"url": "https://example.com/one"},
{"url": "https://example.com/two", "alias": "product-launch"},
{"url": "nope"}
],
"expiresOn": 1790000000
}'
{
"created": 2,
"failed": 1,
"results": [
{
"url": "nope",
"short": null,
"code": null,
"success": false,
"error": "Wrong URL format."
},
{
"url": "https://example.com/one",
"short": "https://ivi.to/Aipw",
"code": "Aipw",
"success": true,
"error": null
},
{
"url": "https://example.com/two",
"short": "https://ivi.to/product-launch",
"code": "product-launch",
"success": true,
"error": null
}
]
}
| Field | Type | Description |
|---|---|---|
created |
integer | How many links were created. |
failed |
integer | How many rows did not produce a link. |
results |
array | One row per link you sent, described below. Not in the order you sent them. |
results[].url |
string | The destination from your request, which is how you match a row back to your input. |
results[].short |
string or null | The finished short link, or null if this row failed. |
results[].code |
string or null | The code alone, or null if this row failed. |
results[].success |
boolean | Whether this row produced a link. |
results[].error |
string or null | Why this row failed, in plain words. Null on success. |
- Bulk creation is a paid feature. On a plan without it the whole request is refused with a feature error and nothing is created.
- The entire batch counts as one request against your per-minute rate limit, however many links it carries.
Some rows can fail while others succeed
This is the one endpoint that does not answer all-or-nothing. A batch with a malformed URL in the middle of it still creates every other link, and tells you which one it dropped and why. That is deliberate: a thousand-row import should not be thrown away because row 400 has a typo in it.
So a 200 here does not mean everything worked. Read
failed, and if it is not zero, read the rows.
The result rows are not in the order you sent them. Failures that were
caught before creation come back first, then the links that were created. Match rows to your
input by the url field, never by position. If the same destination appears
twice in your batch, expect two rows carrying it.
What still fails the whole batch
Three things are checked before any link is created, and each of them refuses the entire request:
- A feature your plan does not include. If any row asks for a custom
alias, an expiry or a password, or the batch names a custom domain, and your plan does
not include that, the request is refused with a
featureerror naming it. One row asking for a gated feature stops the batch, so it is worth filtering those out before sending rather than discovering it at row 900. - More than 10,000 links. Split the work and send it as several batches.
- Not enough monthly link allowance for the whole batch. You get a
quotaerror and nothing is created. The batch is never half-applied to fit the remaining allowance.
Rows that simply fail validation, like a URL that is not a URL, are different: they never reach creation, so they cost no allowance and stop nothing. They come back as failed rows.
Aliases in a batch
A row whose alias is already taken fails on its own, with the rest of the batch unaffected. Its error says so in words rather than as a code: the machine-readable alias_taken error belongs to the single-link create, which has just one alias to talk about.
If you are generating aliases yourself, generate them idempotently, from a record id say, so that re-running a failed import produces the same aliases rather than a second set of links pointing at the same places.