slsh.me API v1
Bearer-token auth, JSON in/out, real-time clicks. Base URL: https://api.slsh.me/v1.
Authentication
Every request to /v1/* must include an Authorization: Bearer <token> header. Create tokens at app.slsh.me/settings/api. Tokens are named PATs; revoke any of them individually.
Missing or invalid tokens return 401 {"error": "invalid_token"}.
Pagination
List endpoints (GET /v1/links, GET /v1/links/:slug/clicks) return at most 100 items per page. Pass ?page=N (1-indexed; default 1) to navigate.
Response headers
| Name | Description |
|---|---|
| X-Total-Count | Total items across all pages. |
| Link | RFC 5988 link header with pre-built URLs for next, prev, first, and last — parse this rather than computing page numbers yourself. |
Example. When you ask for page 1 of a 250-item resource, the server replies with:
X-Total-Count: 250
Link: <https://api.slsh.me/v1/links?page=2>; rel="next", <https://api.slsh.me/v1/links?page=1>; rel="first", <https://api.slsh.me/v1/links?page=3>; rel="last"
Walk forward by following rel="next" until it's no longer present.
Sample event payloads
GET
/v1/events/samples
Returns up to 3 recent events from your account for ?event= (link.clicked, link.created or link.expired), shaped exactly like the corresponding webhook deliveries — canned sample data when your account has no matching activity yet. Built for integrations that need example data before any real event has fired (Zapier's sample step reads this endpoint).
Responses
| 200 | Success |
| 401 | Missing or invalid token |
| 422 | Missing or unknown event type |
List your webhooks
GET
/v1/webhooks
Returns the authenticated organisation's webhooks, newest first. The signing secret is never included here — it is shown only once, in the response to the create call.
Responses
| 200 | Success |
| 401 | Missing or invalid token |
Create a webhook
POST
/v1/webhooks
Registers an endpoint that receives a signed POST on each matching event. link.clicked fires on every recorded visit with the click's geo / device / referer / UTM payload; link.created fires when a link is created, though not for links created by a CSV import — a bulk import would fan out one event per row and overrun the per-webhook delivery rate limit, so imports are skipped entirely rather than delivered in part; link.expired fires once when a link passes its expires_at or max_clicks threshold. The response includes the signing secret — store it now, it is never returned again. Verify deliveries with the X-Slsh-Signature header (HMAC-SHA256 of the raw body, keyed on the secret).
Body parameters
| Name | Type | Required | Description |
|---|---|---|---|
| url | String | required | HTTPS endpoint that will receive the POST |
| event_types | Array | Events to subscribe to. Defaults to ["link.clicked"]. Supported: link.clicked, link.created, link.expired. | |
Responses
| 201 | Created |
| 401 | Missing or invalid token |
| 422 | Invalid params (non-https url, unknown event type, or per-org cap reached) |
Fetch a webhook
GET
/v1/webhooks/:id
Returns a single webhook by id. The signing secret is never included.
Responses
| 200 | Success |
| 401 | Missing or invalid token |
| 404 | Unknown webhook, or it belongs to another organisation |
Delete a webhook
DELETE
/v1/webhooks/:id
Permanently removes the webhook. No further deliveries are attempted.
Responses
| 204 | Deleted |
| 401 | Missing or invalid token |
| 404 | Unknown webhook, or it belongs to another organisation |
List your short links
GET
/v1/links
Returns the authenticated user's default-domain links, newest first. Paginated with ?page=N (1-indexed, 100/page). The response carries X-Total-Count and a standard Link header (RFC 5988) with next, prev, first, last URLs. Links on your custom domains aren't returned here — those are managed via the web app and live in a separate per-domain namespace.
Responses
| 200 | Success |
| 401 | Missing or invalid token |
Create a short link
POST
/v1/links
Creates a short link from a long URL. Slug is auto-generated if omitted.
Body parameters
| Name | Type | Required | Description |
|---|---|---|---|
| url | String | required | The destination URL (http or https) |
| slug | String | Custom slug; must be globally unique on slsh.me. (Links on your custom domains have their own per-domain namespace, but those are managed via the web app — this endpoint always creates a default-domain link.) | |
| password | String | Password-protect the redirect | |
| expires_at | String | ISO 8601 expiry timestamp | |
| max_clicks | Integer | Auto-expire after N clicks | |
| og_title | String | Open Graph title | |
| og_description | String | Open Graph description | |
| mask | boolean | Serve the destination inside a masked iframe (the short URL stays in the address bar). Pro plans only. | |
| notify_on_mask_break | boolean | Email the author if a masked destination later starts blocking framing. | |
Responses
| 201 | Created |
| 401 | Missing or invalid token |
| 422 | Invalid params, or masking requested without a Pro plan |
Fetch a link by slug
GET
/v1/links/:slug
Responses
| 200 | Success |
| 401 | Missing or invalid token |
| 403 | Slug belongs to another user |
| 404 | Unknown slug |
Update a link
PATCH
/v1/links/:slug
Updates the destination URL or metadata. The slug is immutable; any slug in the body is ignored.
Body parameters
| Name | Type | Required | Description |
|---|---|---|---|
| url | String | Replace the destination URL | |
| password | String | Set or change the password | |
| expires_at | String | ISO 8601 expiry timestamp | |
| max_clicks | Integer | Auto-expire after N clicks | |
| og_title | String | Open Graph title | |
| og_description | String | Open Graph description | |
| mask | boolean | Serve the destination inside a masked iframe (the short URL stays in the address bar). Pro plans only. | |
| notify_on_mask_break | boolean | Email the author if a masked destination later starts blocking framing. | |
Responses
| 200 | Updated |
| 401 | Missing or invalid token |
| 403 | Slug belongs to another user |
| 404 | Unknown slug |
| 422 | Invalid params, or masking requested without a Pro plan |
Delete a link
DELETE
/v1/links/:slug
Permanently deletes the link and cascades to its click history.
Responses
| 204 | Deleted |
| 401 | Missing or invalid token |
| 403 | Slug belongs to another user |
| 404 | Unknown slug |
Who am I
GET
/v1/me
Returns the user and organisation this token is scoped to. The cheapest way to verify a token — integrations (Zapier among them) test credentials against this endpoint.
Responses
| 200 | Success |
| 401 | Missing or invalid token |
List clicks for a link
GET
/v1/links/:link_slug/clicks
Returns the click stream (visits) for a default-domain link you own, newest first. Paginated with ?page=N (1-indexed, 100/page). The response carries X-Total-Count and a standard Link header (RFC 5988) with next, prev, first, last URLs.
Responses
| 200 | Success |
| 401 | Missing or invalid token |
| 403 | Link belongs to another user |
| 404 | Unknown link slug |
Look up a link's stats
GET
/v1/links/:link_slug/stats
Aggregate click stats for a default-domain link you own: lifetime totals, human/bot split, last click, expiry state, and the top countries, referrers and devices (top 5 each, all clicks included).
Responses
| 200 | Success |
| 401 | Missing or invalid token |
| 403 | Link belongs to another user |
| 404 | Unknown link slug |