Skip to content

Documentation

Share a file

POST/v1/dropsDrops

Send the file as the request body and get a short link to it. snip.link/<code> shows the file with a download button and its QR code, snip.link/<code>.<its extension> is the file itself, and any other ending converts it (.pdf, .png, .md ...). Send Content-Length; name the file with ?name= or an X-File-Name header. Free shares files up to 100 MB and keeps 5 GB of them; Pro shares files up to 5 GB and keeps 100 GB. Programs and installers are never accepted. The same works without an API: curl -T photo.jpg https://snip.link. Also available as the MCP tool drop_file.

Parameters

ParameterTypeRequiredDescription
namestringoptionalThe file's name.
endingstringoptionalA custom ending for the link.
titlestringoptionalA title for your dashboard; the file's name when left out.
expires_atstringoptionalWhen the link stops working (ISO 8601). Files are kept until then, or for good when left out.

Example request

curl -s -X POST "https://snip.link/v1/drops?name=spring-menu.pdf&ending=menu" \
  -H "Authorization: Bearer $SNIP_KEY"

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,
    "starts_at": null,
    "scheduled": false,
    "max_clicks": null,
    "limit_reached": false,
    "track": true,
    "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,
    "preview": {
      "title": "Spring menu",
      "description": "Twelve new dishes, out now.",
      "image": "screenshot"
    },
    "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",
    "watch": null,
    "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.starts_atstring, nullWhen the link goes live: an ISO date-time, a minute to ten years ahead. Before it a visit gets a "not live yet" page (404) and is not counted, and saved copies stay private. Null removes it. Must come before expires_at. Free on every plan.
link.scheduledbooleanTrue while starts_at is still ahead.
link.max_clicksinteger, nullStop the link after this many counted visits in total (1 to 10,000,000), counting the clicks it already has. Counted means what clicks counts: bots, link previews and repeat taps from one network within a minute are not. The visit that reaches it still goes through; after it the link answers like an expired one (expired_url or a 410), within a minute everywhere. Raising or removing the limit reopens it. Null removes it. Free on every plan.
link.limit_reachedbooleanTrue once the link reached max_clicks.
link.trackbooleanFalse: visits are only counted (clicks still rises, max_clicks still applies), with no record of when, where, on what device or from which site. True (the default): every counted visit is recorded for analytics. Free on every plan.
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.previewLinkPreviewThe link's own social preview: the title, line and picture chat apps and social sites (iMessage, WhatsApp, Slack, Discord, X, LinkedIn, Facebook and the like) show when the short link is pasted, in place of the destination's own. Any field left out falls back to the destination's. image is an https address of a picture, or screenshot for the page's first screen from the link's newest public saved copy. Null clears it. 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.watchWatchThe page watch: a fresh copy of the page daily or weekly, its words compared with the last look's, and an email to the owner listing what was added and what went when they differ. Null while the page is not watched.
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.
409The ending is taken or reserved. Pick another.
413The input is larger than the plan allows per run. details carries the size, the limit and the unit.
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