API

Reference

The key is a secret. Do not call this API from a page you publish, a mobile app you ship, or a public repository. A visitor can read the key out of the page and spend your quota. Server-side code, a GitHub Actions secret, and an MCP client config on your machine are the places it belongs. The dashboard stores a key in localStorage on that browser only.

Request

GET /v1/preview?url=<absolute url>&platforms=x,slack&source=api

POST /v1/preview with a JSON body accepts the same fields. platforms is optional (all 11 apps when omitted). source is api, mcp, or action. It only changes which counter we increment. The default is api.

Header: Authorization: Bearer cs_live_…. The token is at least 32 characters after cs_live_.

GET responses send Access-Control-Allow-Origin: *. That does not make a browser call safe. The key is still visible to anyone who can read the request.

curl

curl -sS "https://cardscope.dev/v1/preview?url=https://example.com&source=api" \
  -H "Authorization: Bearer cs_live_…"

JavaScript

const res = await fetch(
  "https://cardscope.dev/v1/preview?url=" + encodeURIComponent("https://example.com"),
  { headers: { Authorization: `Bearer ${process.env.CARDSCOPE_API_KEY}` } },
);
const preview = await res.json();

Python

import os, requests
res = requests.get(
    "https://cardscope.dev/v1/preview",
    params={"url": "https://example.com", "source": "api"},
    headers={"Authorization": f"Bearer {os.environ['CARDSCOPE_API_KEY']}"},
    timeout=20,
)
preview = res.json()

Response

The TypeScript shape is LinkPreview in src/lib/preview.ts.

Errors

Quotas

Free 300, Starter 10,000, Pro 100,000 previews each UTC month. The counter key is api:{keyId}:{YYYY-MM}, so the next month starts at zero. A rejected URL (400) and a rate-limited call (429) do not count. A fetch we attempt does, including a 422.

Keys

POST /api/keys with {"email":"you@example.com"} emails a one-time link. GET /api/keys/claim?token=… shows the key once. GET /api/keys/me returns the plan and this month’s usage. POST /api/keys/rotate returns a new key and revokes the one you sent. POST /api/keys/upgrade with {"plan":"starter"} or "pro" returns a Stripe Checkout URL. POST /api/keys/portal returns a billing portal URL after the first payment.