API v1
Minimal public docs
for the SHAER API.
Everything needed to authenticate, create links, update them, delete them safely, inspect analytics, and manage branded domains.
Authentication
Authenticate every request with a SHAER API key using the `Authorization: Bearer ...` header. Keys are shown once at creation time, stored hash-only, and cannot be retrieved later.
Authorization: Bearer sk_live_xxxxxxxxxxxxxxxxx
Create key: POST /api/dashboard/api-keys/create
Revoke key: POST /api/dashboard/api-keys/revokeCreate Link
Create a short link for an authenticated account.
POST /api/v1/links
{
"destination": "https://example.com"
}Update Link
Update destination, status, slug, or metadata on an owned link.
PATCH /api/v1/links/:id
{
"destination": "https://new-url.com",
"status": "disabled",
"slug": "new-custom-slug"
}Delete Link
Soft delete a link. It disappears from active product surfaces while history and routing events remain preserved.
DELETE /api/v1/links/:idAnalytics
Fetch lightweight programmable analytics for a single owned link.
GET /api/v1/links/:id/analytics
{
"clicks": 182,
"recentActivity": [],
"topReferrers": [],
"topDestinations": [],
"timeline": []
}Domains
Add, verify, rename, disable, and mark branded routing domains as primary from the dashboard or domain endpoints.
POST /api/domains
PATCH /api/domains/:id
POST /api/domains/verifyWebhooks
Register webhook endpoints to receive `link.clicked`, `link.disabled`, and `link.deleted` events as signed JSON POST payloads. SHAER signs the raw payload with HMAC SHA-256 and sends it in `x-shaer-signature`.
POST /api/webhooks
POST /api/webhooks/revoke
POST /api/webhooks/test
Header: x-shaer-signature
{
"name": "Production events",
"url": "https://hooks.example.com/shaer",
"events": ["link.clicked", "link.disabled"]
}Verify In Node
Minimal raw-body verification in plain Node.
import { createHmac } from "node:crypto";
const expected = "sha256=" + createHmac("sha256", process.env.SHAER_WEBHOOK_SECRET)
.update(rawBody)
.digest("hex");Verify In Next.js
Minimal verification inside a Route Handler with `await req.text()`.
export async function POST(req: Request) {
const rawBody = await req.text();
const signature = req.headers.get("x-shaer-signature");
}Verify In Express
Minimal verification with `express.raw` so the payload stays untouched.
app.post("/shaer", express.raw({ type: "application/json" }), (req, res) => {
const rawBody = req.body.toString("utf8");
const signature = req.get("x-shaer-signature");
});Errors
SHAER uses straightforward JSON errors with consistent HTTP codes: `401` unauthorized, `403` forbidden, `404` not found, `409` conflict.
{
"success": false,
"error": "Forbidden"
}Rate Limits
API access is reserved for Expert. The public pricing model still defines the underlying distribution ceilings by plan.
FREE → No API
PRO → No API
EXPERT → Unlimited records • 1000 req/min