API Docs

Authentication.

A Bearer key per user, a supporter subscription on their account, and two rate budgets.

425 words · ~2 min read

Every endpoint takes an API key in the Authorization header:

Authorization: Bearer sc_...

The app's own login tokens are not API keys. Sending one gets the same 401 as a wrong key.

Keys

Users mint keys in the app under Settings → Integrations → API. The full key is shown once, then only its hash is kept server-side. They can also see each key's label, creation date and last use, and revoke it from the same place.

  • An account holds at most 3 active keys. Revoking one frees the slot.
  • Keys start with sc_. Older keys start with drk_ and keep working. The prefix is cosmetic, the hash is what authenticates.
  • Revoked or wrong key: 401 {"error": "unauthorized", "message": "invalid API key"}.
  • No header at all: 401 with the message missing API key (Authorization: Bearer sc_...).
  • The account's own name for the key shows up in the app's last-trigger feed as api:<label>, so a label like your product name helps the user recognise you.

Supporter gate

The relayed endpoints need an active supporter subscription on the key's account, managed at account.kinkyraven.com. Verified creator accounts count as supporters. Without either you get:

{"error": "patreon_required", "message": "the API requires an active supporter subscription on the linked account"}

The status is 403. The code keeps its historical name for compatibility, so match on patreon_required even though Patreon is only one of the payment routes.

GET /relay/me is exempt. It reports the gate as patreon.active instead of enforcing it, so you can tell "key works, user needs to subscribe" from "key is dead".

Firing at a friend also checks the friend's subscription, not only yours. See the friend endpoints.

Rate limits

Two fixed 60-second budgets, both spent by every call made with an API key:

  • 120 requests per minute per key.
  • 240 requests per minute per account, all keys summed.

There is no separate trigger budget. Triggers count like any other call. Past either limit:

{"error": "rate_limited", "message": "API rate limit exceeded", "retryAfter": 47}

The status is 429 and the same number arrives as a Retry-After header, in seconds until the window resets. GET /relay/me returns used_this_window so you can watch the counters, and the call itself counts.

Friend endpoints have extra, smaller budgets on top of these. They are listed per endpoint.

Repeated calls with a missing or invalid key are also throttled per IP, 30 failures in 10 minutes. Cache the fact that a key is dead rather than retrying it.