Skip to content

Documentation

Finish an upload

POST/v1/drops/uploads/{id}/completeDrops

Puts 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

ParameterTypeRequiredDescription
idstring, in the pathrequiredThe upload's id.

Request body

JSON, sent with Content-Type: application/json.

FieldTypeRequiredDescription
endingstringoptionalAnother 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

FieldTypeDescription
linkLink
link.idstringStable id. Every link route accepts it, or a current or previous ending.
link.codestringThe current ending: the path after the domain.
link.domainstringThe hostname the link lives on: snip.link, or one of the account's own domains.
link.short_urlstringThe short link, ready to share or print.
link.urlstringWhere the link goes now. Change it any time; printed codes follow.
link.titlestring, nullA name for the dashboard. Null when unset.
link.redirectinteger302 (default: every scan is counted) or 301 (browsers may cache the hop).
link.disabledbooleanA disabled link answers 404 until it is enabled again.
link.heldbooleanTrue 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_atstring, nullWhen the link stops sending people to url, or null.
link.expired_urlstring, nullWhere the link sends people after it expires; null shows a plain 'link expired' page (410). Checked like a destination.
link.expiredbooleanTrue once expires_at has passed.
link.password_protectedbooleanTrue when visitors must enter a password first. The password is never returned.
link.routesarray, nullRules, or null.
link.forward_querybooleanWhen 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.healthobjectThe 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.clicksintegerEvery click and scan since the link was made.
link.qr_styleQrStyleHow the link's QR code is drawn in the dashboard and at its image URLs.
link.qr_png_urlstringThe link's QR code as PNG (512 px). Free, no key.
link.qr_svg_urlstringThe same code as SVG, for print.
link.snapshotspublic | private | offWho 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.fileFileThe 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_urlstring, nullThe 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_atstring
link.updated_atstring

Errors

StatusMeaning
400The body or query is invalid. details names each field.
401The API key is missing, malformed or revoked.
403The plan does not include this. details.upgrade names the plan that does.
404No link by that id or ending in this account.
409The ending is taken or reserved. Pick another.
429Either the key exceeded its requests-per-second limit (honor Retry-After), or a daily or plan quota is used up (details.reason).

Back to getting started