> ## Documentation Index
> Fetch the complete documentation index at: https://docs.keyport.sbs/llms.txt
> Use this file to discover all available pages before exploring further.

# Security

> Recommended practices for integrating with KeyPort safely.

Follow these practices when integrating KeyPort to protect your product API keys, your users, and your application logic.

## Store API keys safely

Your product API key authenticates all requests to the public API. Treat it like a password.

* Store it in an environment variable or a secure config file, never in source code
* Never embed it in client-side code — it will be visible to anyone who inspects your bundle
* Log only the key prefix for debugging purposes, never the full token

<Warning>
  If your product API key is exposed, rotate it immediately. The old key is invalidated as soon as you rotate it.
</Warning>

## Validate server-side

Call the KeyPort public API from your backend, not from the browser or any user-controlled environment. Validating on the server keeps your product API key out of reach and prevents users from bypassing license checks.

<Tip>
  If you need to surface license status in a client-side UI, expose a thin endpoint on your own backend that proxies the validation result — never the raw KeyPort response including the API key.
</Tip>

## Verify webhook signatures

Every delivery from KeyPort includes an `X-KeyPort-Signature` header. Always verify this signature before processing the payload.

Skipping signature verification means any party could send a forged request to your webhook endpoint and trigger your application logic.

See [Payloads & Signing](/webhooks/payloads-and-signing) for a working code example of signature verification.

<Warning>
  Do not process webhook payloads without first verifying the `X-KeyPort-Signature` header. Unverified deliveries can be spoofed.
</Warning>

## Handle statuses explicitly

KeyPort returns typed statuses rather than a generic success/failure response. Your application should branch on each relevant status rather than treating all non-success cases the same way.

The statuses you may need to handle include:

* **Expiry** — the license has passed its expiration date
* **Revocation** — the license has been explicitly revoked
* **IP policy** — the request came from an IP that does not pass the product's IP rules
* **Billing suspension** — the license is suspended due to a billing issue
* **Configuration failure** — a product or license configuration problem prevented validation

<Tip>
  Mapping each status to a specific user-facing message or action improves the experience for your customers and makes debugging easier for you.
</Tip>
