This is the public integration API for Moonshot Games's short link service. There is exactly one write endpoint exposed for external apps; everything else is admin-only.
All API requests require a key minted from the admin panel. Pass it as a Bearer token:
Authorization: Bearer msr_xxxxxxxxxxxxxxxx
Or, if your client can't set Authorization, use the header X-API-Key instead.
https://msrips.com/api
A slug is the short tail of the URL — e.g. in https://msrips.com/jay the slug is jay.
a-z, 0-9). No symbols, no underscores, no hyphens./JAY, /Jay, and /jay all resolve to the same link. The server lowercases everything on input and lookup.admin, api, r, docs, etc. are rejected.POST/api/links
| Field | Type | Required | Notes |
|---|---|---|---|
longUrl | string | yes | Must be a valid http(s) URL. |
customSlug | string | no | Vanity slug. See slug rules above. Omit to get an auto-generated slug. |
domain | string | no | Hostname to build the short URL against. Defaults to the configured default domain. |
| Status | Meaning |
|---|---|
| 200 | Idempotent hit. A link with the requested customSlug already exists and already points to the same longUrl + domain. Body is the existing Link. Safe to call repeatedly. |
| 201 | Created. Body is the new Link. |
| 400 | Body missing/malformed, longUrl not a valid http(s) URL, or invalid/reserved slug format. |
| 401 | Missing or invalid API key. |
| 409 | Slug conflict. The slug exists and points to a different URL. Body includes the existing record so you can negotiate (see below). |
| 500 | Slug generation or insert failed. Safe to retry. |
Link{
"id": 42,
"slug": "jay",
"longUrl": "https://stream.moonshot.games/clips/abc123",
"domain": "msrips.com",
"custom": true,
"createdAt": "2026-05-03T18:22:11.000Z",
"shortUrl": "https://msrips.com/jay"
}
Always use the returned shortUrl verbatim — don't reconstruct it client-side, since the response domain may differ from the request host.
409{
"error": "Slug \"jay\" is already in use",
"existing": {
"id": 17,
"slug": "jay",
"longUrl": "https://different.example.com/page",
"domain": "msrips.com",
"custom": true,
"createdAt": "2026-04-12T09:01:33.000Z",
"shortUrl": "https://msrips.com/jay"
}
}
Recommended client flow on 409:
jay currently points to (existing.longUrl).customSlug and retry, or accept the existing shortUrl as-is.customSlug + longUrl after a network hiccup, you'll get a 200 with the original record instead of a 409. You can rely on this.Auto-generated slug:
curl -X POST https://msrips.com/api/links \
-H "Authorization: Bearer msr_xxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{"longUrl":"https://stream.moonshot.games/clips/abc123"}'
# → 201 { ..., "shortUrl": "https://msrips.com/k3p" }
Vanity slug:
curl -X POST https://msrips.com/api/links \
-H "Authorization: Bearer msr_xxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{"longUrl":"https://stream.moonshot.games/jayson","customSlug":"jay"}'
# → 201 { ..., "shortUrl": "https://msrips.com/jay" }
# → 200 if the same { customSlug, longUrl } pair was already created (idempotent)
# → 409 if "jay" already maps to a different longUrl
GET/api/links/<slug>/stats
Returns the link plus its total click count and last-clicked timestamp. Accessible with the same API key (or an admin session). Poll this to display click counts in your own app.
curl https://msrips.com/api/links/jay/stats \
-H "Authorization: Bearer msr_xxxxxxxxxxxxxxxx"
LinkStats{
"id": 42,
"slug": "jay",
"longUrl": "https://stream.moonshot.games/clips/abc123",
"domain": "msrips.com",
"custom": true,
"createdAt": "2026-05-03T18:22:11.000Z",
"shortUrl": "https://msrips.com/jay",
"clickCount": 137,
"lastClickAt": "2026-05-04T11:09:52.000Z"
}
lastClickAt is null if the link has never been clicked. Slug lookup is case-insensitive. Returns 404 if the slug doesn't exist.
No API call is needed to resolve a short link — just hit the URL. The service issues a 302 redirect to the underlying longUrl and records the click. Both forms work and are equivalent:
GET https://msrips.com/<slug> → 302 Location: <longUrl>
GET https://msrips.com/r/<slug> → 302 Location: <longUrl>
Lookups are case-insensitive: /JAY and /jay both work. Always advertise the lowercase form returned in shortUrl.
customSlug. Calls without it mint a fresh slug every time, even for the same longUrl.Questions, or a key revoked by mistake? Reach Jayson at Moonshot Games.