# Security

What Onekey does to protect your keys and your calls, and what you should do on your side. This page lists only controls that exist in the API today; it makes no certification claims.

## How a request moves

1. You send `x-api-key` over HTTPS. The key is looked up by its hash.
2. The request is checked against the key's rate limit, its credit limit and your balance before anything is fetched.
3. The platform is fetched, the result is mapped to the [unified schema](https://onekey.dev/docs/schema.md), cached, and returned.
4. Every answer carries `Cache-Control: private, no-store`, so no CDN or shared proxy keeps your data.

## What Onekey reads

Onekey returns public data only. It does not log in to platforms as you or as anyone else, and it does not read private accounts or messages. See [Public data](https://onekey.dev/public-data), the [acceptable use policy](https://onekey.dev/aup) and the [data processing terms](https://onekey.dev/dpa).

## Your API keys

- **Only a hash is stored.** A key is shown once, when you create it. What we keep is a peppered HMAC-SHA256 hash, so a copy of our database does not contain usable keys. Lose a key and you create a new one; it cannot be shown again.
- **One key per app and environment.** Revoke one without touching the rest from [the dashboard](https://onekey.dev/dashboard/keys).
- **Cap each key.** A [credit limit](https://onekey.dev/docs/key-limits.md) bounds what a leaked or runaway key can spend.
- **Server side only.** Never put a key in browser code, a mobile app bundle or a public repository. See [Authentication](https://onekey.dev/docs/authentication.md).
- **Wrong keys are throttled.** Repeated bad-key attempts from one address are limited separately, so guessing keys does not work. See [Rate limits](https://onekey.dev/docs/rate-limits.md#bad-key-attempts).
- **Rotate on suspicion.** Create a new key, deploy it, then revoke the old one.

## Webhooks

- Every monitor delivery is signed: `Onekey-Signature: t=<unix>,v1=<hmac-sha256>` over the timestamp and the raw body, with a per-monitor secret you can rotate (`POST /v1/monitors/{id}/webhook/rotate`). Verify it and refuse a timestamp more than 300 seconds off. See [Verify the signature](https://onekey.dev/docs/monitors.md#verify-the-signature).
- A webhook URL must be `https` on port 443 to a public host. Private, loopback and link-local addresses are refused at creation and again at delivery, and redirects are never followed. See [Webhook URL rules](https://onekey.dev/docs/monitors.md#webhook-url-rules-ssrf).

## Requests that fetch a URL

Endpoints that take a URL (the web tools, [URL lookup](https://onekey.dev/docs/lookup.md)) fetch only public internet hosts. Addresses that resolve to private or internal ranges are refused, so a URL parameter cannot be used to reach anything inside our network.

## What you should do

- Keep the key in a secret store and out of logs. Log `request_id` instead.
- Use a capped key per environment.
- Verify webhook signatures on the raw body.
- Treat everything in `data` as untrusted text from a third party (a post can contain anything). Escape it before rendering and do not execute it. If you pass it to an AI model, treat it as untrusted input there too.

## Reporting a problem

Found a vulnerability or abuse of the service? See [Abuse](https://onekey.dev/abuse) for where to report it.

## Next

- [Production checklist](https://onekey.dev/docs/production-checklist.md).
- [Authentication](https://onekey.dev/docs/authentication.md).
