Documentation
Finish an upload
POST
/v1/drops/uploads/{id}/completeDropsPuts the parts together, checks the file and makes its link: the same answer as Share a file. A large file takes a few seconds per gigabyte. Asking again after a lost answer returns the same link; if the ending was taken meanwhile, ask again with another ending.
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | string, in the path | required | The upload's id. |
Request body
JSON, sent with Content-Type: application/json.
| Field | Type | Required | Description |
|---|---|---|---|
ending | string | optional | Another ending than the one the upload started with. |
Example request
curl -s -X POST "https://snip.link/v1/drops/uploads/id/complete" \
-H "Authorization: Bearer $SNIP_KEY" \
-H "Content-Type: application/json" \
-d '{}'Example response
{
"link": {
"id": "lnk_7f0c2a2b4bb04a8b",
"code": "spring-menu",
"domain": "snip.link",
"short_url": "https://snip.link/spring-menu",
"url": "https://example.com/menus/spring-2026",
"title": "Spring menu",
"redirect": 302,
"disabled": false,
"held": false,
"expires_at": null,
"expired_url": null,
"expired": false,
"password_protected": false,
"routes": [
{
"when": "all",
"conditions": [
{
"kind": "os",
"values": [
"ios"
]
}
],
"url": "https://apps.apple.com/app/id1234567890",
"match": "ios"
},
{
"name": "Lunch menu",
"when": "all",
"conditions": [
{
"kind": "time",
"from": "11:00",
"to": "15:00",
"tz": "America/New_York"
},
{
"kind": "weekday",
"values": [
1,
2,
3,
4,
5
],
"tz": "America/New_York"
}
],
"url": "https://example.com/menus/lunch"
}
],
"forward_query": false,
"health": {
"status": "ok",
"code": 200,
"checked_at": "2026-10-20T08:00:00.000Z"
},
"clicks": 1284,
"qr_style": {
"style": "rounded",
"fg": "#111111",
"bg": "#ffffff",
"ecc": "M"
},
"qr_png_url": "https://snip.link/qr.png?data=https%3A%2F%2Fsnip.link%2Fspring-menu%3Fqr%3D1",
"qr_svg_url": "https://snip.link/qr.svg?data=https%3A%2F%2Fsnip.link%2Fspring-menu%3Fqr%3D1",
"snapshots": "public",
"file": null,
"stats_url": null,
"created_at": "2026-10-01T09:12:40.000Z",
"updated_at": "2026-10-18T16:03:11.000Z"
}
}Response fields
| Field | Type | Description |
|---|---|---|
link | Link | |
link.id | string | Stable id. Every link route accepts it, or a current or previous ending. |
link.code | string | The current ending: the path after the domain. |
link.domain | string | The hostname the link lives on: snip.link, or one of the account's own domains. |
link.short_url | string | The short link, ready to share or print. |
link.url | string | Where the link goes now. Change it any time; printed codes follow. |
link.title | string, null | A name for the dashboard. Null when unset. |
link.redirect | integer | 302 (default: every scan is counted) or 301 (browsers may cache the hop). |
link.disabled | boolean | A disabled link answers 404 until it is enabled again. |
link.held | boolean | True while the link is switched off for a safety review. A held link cannot be changed or enabled (403 forbidden, details.reason link_held); it can be deleted. |
link.expires_at | string, null | When the link stops sending people to url, or null. |
link.expired_url | string, null | Where the link sends people after it expires; null shows a plain 'link expired' page (410). Checked like a destination. |
link.expired | boolean | True once expires_at has passed. |
link.password_protected | boolean | True when visitors must enter a password first. The password is never returned. |
link.routes | array, null | Rules, or null. |
link.forward_query | boolean | When true, a visit's own query parameters (?ref=ig and the like) are added to the destination, replacing a parameter of the same name; Snip's qr marker is never passed on. Free on every plan. |
link.health | object | The destination check: every link's destination is fetched every few days. failing after two failed checks in a row (a 404, a 410, a server error or no answer); sites that refuse automated visitors are not counted as failing. |
link.clicks | integer | Every click and scan since the link was made. |
link.qr_style | QrStyle | How the link's QR code is drawn in the dashboard and at its image URLs. |
link.qr_png_url | string | The link's QR code as PNG (512 px). Free, no key. |
link.qr_svg_url | string | The same code as SVG, for print. |
link.snapshots | public | private | off | Who can read the link's saved copies. public: anyone with the link, at the link's format endings (snip.link/abc.md, .pdf ...), and the first one asked for saves the page. private: only you, through the signed URLs the API returns. off: no copies are made. |
link.file | File | The file, when the link is a shared file (docs/drops.md): the link shows it instead of redirecting. Null for an ordinary link. |
link.stats_url | string, null | The link's public stats page (totals by day, country, referring site and device for the last 30 days), when the owner shared it with stats_public; null while the stats are private. |
link.created_at | string | |
link.updated_at | string |
Errors
| Status | Meaning |
|---|---|
| 400 | The body or query is invalid. details names each field. |
| 401 | The API key is missing, malformed or revoked. |
| 403 | The plan does not include this. details.upgrade names the plan that does. |
| 404 | No link by that id or ending in this account. |
| 409 | The ending is taken or reserved. Pick another. |
| 429 | Either the key exceeded its requests-per-second limit (honor Retry-After), or a daily or plan quota is used up (details.reason). |