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

# Security Best Practices

> Best practices for API key storage, key rotation, transport security, and webhook endpoint protection.

# Security Best Practices

## API key storage

Store API keys in a secrets manager or environment variables. Never hardcode them in source code.

| Approach                                                         | Recommended                                            |
| ---------------------------------------------------------------- | ------------------------------------------------------ |
| Environment variables                                            | Yes. Minimum acceptable approach.                      |
| Secrets manager (AWS Secrets Manager, Vault, GCP Secret Manager) | Yes. Preferred for production.                         |
| Configuration file (`.env`, `config.yaml`)                       | Only if gitignored and encrypted at rest.              |
| Hardcoded in source code                                         | No. Never.                                             |
| Client-side JavaScript                                           | No. Keys are visible to anyone with browser dev tools. |
| Mobile app bundles                                               | No. APKs and IPAs can be decompiled.                   |

<Warning>
  Never hardcode API keys in source code, client-side JavaScript, or mobile app bundles. Keys in these locations are trivially extractable and cannot be considered secret.
</Warning>

<CodeGroup>
  ```bash Shell theme={null}
  # Set via environment variable
  export ZENOO_API_KEY="your-api-key"
  export ZENOO_WEBHOOK_SECRET="your-webhook-secret"
  ```

  ```javascript Node.js theme={null}
  // Read from environment
  const apiKey = process.env.ZENOO_API_KEY;
  const webhookSecret = process.env.ZENOO_WEBHOOK_SECRET;
  ```

  ```python Python theme={null}
  import os
  api_key = os.environ["ZENOO_API_KEY"]
  webhook_secret = os.environ["ZENOO_WEBHOOK_SECRET"]
  ```
</CodeGroup>

## Key rotation

Rotate API keys on a regular schedule and immediately after any suspected compromise.

**Planned rotation.** Prepare your deployment pipeline before requesting a new key. The old key is revoked the moment the new one is issued. There is no overlap period.

<Steps>
  <Step title="Prepare configurations">
    Update all application configurations and CI/CD secrets to accept the new key.
  </Step>

  <Step title="Request rotation">
    Request rotation from Zenoo support.
  </Step>

  <Step title="Receive the new key">
    Receive the new key from Zenoo support.
  </Step>

  <Step title="Deploy immediately">
    Deploy the new key to all environments immediately after receiving it.
  </Step>
</Steps>

<Warning>
  **Emergency rotation.** If a key is exposed in a public repository, log file, or client-side code, contact Zenoo support immediately. The compromised key will be revoked and a new one issued.
</Warning>

## Transport security

<Note>
  All API communication must use HTTPS. Zenoo does not accept HTTP requests. Use TLS 1.2 or higher.
</Note>

* Verify server certificates. Do not disable certificate validation in production.
* Pin certificates if your security policy requires it.

## IP allowlisting

Contact Zenoo support to configure IP allowlisting for your API keys. When enabled, requests from IPs outside the allowlist are rejected with `403 Forbidden`.

Considerations:

* Provide the public IP addresses or CIDR ranges of your application servers.
* Update the allowlist before deploying to new infrastructure.
* Cloud-hosted applications with dynamic IPs may need a NAT gateway or static IP assignment.

## Webhook endpoint security

Your webhook endpoint receives verification results that may contain personally identifiable information. Protect it accordingly.

**Verify signatures.** Always validate the `X-Zenoo-Signature` header before processing any webhook payload. See [Webhook Signatures](/guides/webhooks#signature-verification) for implementation details.

**Use HTTPS.** Your webhook endpoint must be accessible over HTTPS. Zenoo will not deliver webhooks to HTTP URLs.

**Respond quickly.** Return `200 OK` within 30 seconds. Queue the payload for async processing rather than performing business logic in the request handler.

**Log failures.** Record every failed signature verification with the timestamp, source IP, and request headers. A pattern of failures may indicate someone is probing or spoofing your endpoint.

**Restrict access.** If possible, configure your firewall or load balancer to only accept webhook requests from Zenoo's IP ranges. Contact Zenoo support for the current list.

## Monitoring

<Tip>
  Track these metrics to detect issues early. Set up automated alerts for any anomalies -- early detection is the best defense against key compromise and integration failures.
</Tip>

| Metric                                  | What to watch                                                        |
| --------------------------------------- | -------------------------------------------------------------------- |
| API error rate by status code           | Spike in `401`/`403` may indicate key compromise or misconfiguration |
| `5xx` error rate                        | Sustained increase suggests provider or infrastructure issues        |
| Webhook delivery success rate           | Failures may indicate endpoint issues or network problems            |
| Webhook signature verification failures | Repeated failures suggest a misconfigured secret or attack           |
| Response latency (p50, p95, p99)        | Increasing latency may indicate provider degradation                 |

**Set up alerts for:**

* `5xx` error rate exceeding 5% over a 10-minute window.
* Any `401` errors (may indicate a rotated or leaked key).
* Webhook signature verification failure rate above 0%.
* Average response time exceeding 2x your baseline.

**Log the `request_id`** from every API response. When contacting Zenoo support, include this ID to enable fast diagnosis.

<CodeGroup>
  ```javascript Node.js theme={null}
  const response = await fetch(url, options);
  const data = await response.json();

  if (!response.ok) {
    console.error(`Zenoo API error: ${data.error}`, {
      requestId: data.request_id,
      status: response.status,
      message: data.message
    });
  }
  ```

  ```python Python theme={null}
  response = requests.post(url, headers=headers, json=payload)

  if not response.ok:
      data = response.json()
      logger.error(
          "Zenoo API error: %s (request_id=%s, status=%d)",
          data.get("error"),
          data.get("request_id"),
          response.status_code,
      )
  ```
</CodeGroup>
