ZIPPY DOCS

n8n

Make Zippy a step in your n8n automations — create links mid-workflow, and start a workflow when a tap ACTUALLY opened someone's native app. Two official nodes, plus an HTTP Request recipe that works today.

n8n + Zippy

Most link tools give n8n a node that can tell you a click happened. Zippy's trigger tells you what happened next — whether that tap reached the person's real native app, got trapped in an in-app browser, or broke outright.

That's a branch nobody else can express: if the last twenty taps on this link came back app.browser, swap the destination and DM me.

The nodes aren't installable yet — we haven't published them

@zippy/n8n-nodes-zippy is not on npm. n8n's Settings → Community nodes dialog can't find it, and npm install @zippy/n8n-nodes-zippy resolves to nothing. The package is built, tested (47 tests, including a live check of every route against the API itself) and behaves exactly as described below — publishing it is the remaining step, and it's a founder call that hasn't been made. This page gets the one-line install the day it lands.

In the meantime the HTTP Request recipe below works right now, on any n8n, with no node to install. It's the same API the nodes drive.

With n8n's built-in HTTP Request node against the Zippy API. No community node, no install — Zippy's API is a Legend power, so you need a zip_ key from Settings → API keys.

1. Store the key once. In n8n, create a Header Auth credential:

FieldValue
NameAuthorization
ValueBearer zip_your_key_here

2. Add an HTTP Request node wherever your workflow needs a link:

FieldValue
MethodPOST
URLhttps://api.zipthe.link/v1/links
AuthenticationGeneric → Header Auth → the credential above
Body (JSON){"url": "{{ $json.destination }}", "tags": ["n8n"]}

3. Use {{ $json.shortUrl }} downstream. The response hands back the finished URL — nothing to assemble from slug and hostname.

Every /v1 route is fair game from the same node: GET /v1/links/{id}/stats for app-open outcomes, GET /v1/links/{id}/ab-stats for per-variant results, PUT /v1/bio/blocks to rebuild a bio page. The API reference lists all of them; rate limit is 120 requests per minute per key.

How do I start an n8n workflow when someone opens my app?

This is the part worth building a workflow around, and it also works today — with n8n's Webhook node and a Zippy webhook subscription.

  1. Add a Webhook node (method POST) and copy its production URL. It must be https:// and publicly reachable — Zippy refuses a loopback or private-range callback, because a registered webhook is a request our API makes. Local n8n needs WEBHOOK_URL set to a public address, or a tunnel.
  2. Register that URL in Zippy — dashboard Webhooks, or POST /v1/webhooks — subscribed to app.opened, app.browser and app.broken. Zippy shows the signing secret exactly once; store it.
  3. Verify the signature before you trust the delivery. The webhook URL is public, so the x-zippy-signature HMAC is the only thing standing between your workflow and anyone who can send a POST. Turn on Raw Body on the Webhook node and check the HMAC in a Code node — the exact recipe is in the webhooks docs.
  4. Branch on the event with an IF or Switch node.

Each delivery is the standard envelope:

{
  "event": "app.opened",
  "ts": "2026-07-19T14:03:22.512Z",
  "data": {
    "slug": "summer-drop",
    "shortHost": "zipthe.link",
    "platformKey": "youtube",
    "sourceApp": "instagram",
    "country": "US",
    "city": "Austin",
    "device": "ios",
    "ts": "2026-07-19T14:03:21.900Z"
  }
}

sourceApp is the in-app browser the tap escaped from; platformKey is where it was headed. Webhook subscriptions are a Legend feature, and a workspace can register up to 5.

Push, never poll

Don't build a Schedule trigger that calls /v1/links/{id}/stats every five minutes. An idle webhook-driven workflow makes zero requests to the Zippy API, and no event falls into the gap between two polls.

What will the official nodes add?

Two of them, and the second is the reason for the first.

Zippy Trigger replaces steps 1–3 above with a checkbox list. Activating the workflow registers the subscription for you; deactivating removes it; editing the event list patches the existing subscription instead of burning another of your five. It verifies the HMAC itself, in constant time, and answers an unsigned or mis-signed delivery 401 without starting the workflow. Defaults are ticked to the three app-outcome events, because that's what the node is for.

It flattens the envelope one level so an IF node reads one field:

{
  "event": "app.opened",
  "outcome": "opened",
  "ts": "2026-07-19T14:03:22.512Z",
  "slug": "summer-drop",
  "sourceApp": "instagram",
  "country": "US",
  "device": "ios",
  "data": { "…": "the untouched payload" }
}

outcome is opened / browser / broken for the app.* events and null otherwise.

Zippy is the action node — the HTTP Request recipe, with dropdowns:

ResourceOperations
LinkCreate · Get Many · Update · Archive
AnalyticsApp-Open Outcomes · Click Events · A/B Variants · Workspace Overview
Bio PageGet · Update · Set Blocks · Block App-Open Stats
ContactGet Many · Delete

One credential (Zippy API: your zip_ key plus your API's base URL), sent as Authorization: Bearer. There's no OAuth variant, because /v1 never reads a session cookie — and because a key resolves server-side to exactly one workspace, no parameter on either node takes an org or workspace id. There is no shape of a call that reaches another tenant.

utm, routing, ab, sched, password, pixelIds and hostname go through a single Advanced (JSON) field rather than being modelled as node parameters — the API's own validators are the source of truth for those shapes, and a hand-copied duplicate in a node would drift out of date. An invalid field comes back as a 400 naming it.

How honest are the numbers I branch on?

Honest enough to be worth a warning. App-open rates are sampled estimates from an analytics pipeline, not an audit log:

  • Branch on a trend or a whole-number rate, never a decimal difference between two runs.
  • appOpenRate comes back null, never 0, when nothing has been measured yet. That means no data, not nobody opened it — a workflow that treats it as 0 will page you about silence.
  • configured: false means outcome collection isn't wired up upstream and every number in that response is a placeholder.

The opened/browser/broken split needs Hero or above; lower tiers get totals. Individual webhook deliveries are different — those are per-tap events, not a sample.

Worth knowing before you automate it: Archive hides a link and frees a slot against your plan cap. It does not stop the link redirecting. A Zippy link resolves forever, by design, and no node, endpoint or workflow can change that. If you need a link dead, the honest answer is that Zippy can't do it.

FAQ

Today, with the HTTP Request node pointed at https://api.zipthe.link/v1/links and a Header Auth credential carrying Bearer zip_…. Read {{ $json.shortUrl }} off the response and use it in the next step. An official community node is built but not yet published; when it is, the same call becomes a Zippy → Link → Create dropdown.

Can n8n trigger on whether someone actually opened the app?

Yes, and only with Zippy. Subscribe an n8n Webhook node to app.opened, app.browser and app.broken, and each tap arrives as its own event saying which of the three happened on the device. Every other link tool's trigger fires on a click and stops there — a click can't tell you whether the person landed in the real app or in a webview where they aren't logged in.

Do I need to install anything to use Zippy with n8n?

No. The HTTP Request and Webhook nodes ship with every n8n, and Zippy's side is a plain HTTP API. The community node is convenience, not a requirement — and it isn't on npm yet anyway.

Why does Zippy reject my n8n webhook URL?

Because it isn't https:// on a publicly reachable host. http://localhost:5678/... and private-range addresses are refused by design — registering a webhook means our API will make requests to that URL, and the SSRF guard isn't negotiable. Set WEBHOOK_URL to your public n8n address, or run n8n behind a tunnel.

Which plan do I need?

Legend for both the API key and webhook subscriptions. The app-open split in analytics responses needs Hero or above; below that you get totals. Creating links and reading your own numbers in the dashboard needs neither.

Will my n8n workflows break when the nodes get published?

No. The nodes call exactly the same /v1 routes your HTTP Request nodes call — they're a nicer front end to the same API, not a different one. Migrating is optional.

Read more