> Part of [WHCC Developer Documentation](https://www.whcc.com/developer/llms.txt)

# API Key Security

Version 1.4 &middot; Updated 2026-10-08

Your API key is the entire credential. Whoever holds it can call every endpoint your account can reach, including [`POST /v1/commerce/submissions`](https://www.whcc.com/developer/docs/quick-start/#step-6), which places a real, billable order. Treat the key the way you would treat a saved payment method.

> **The key is a bearer token, so it is server-side only.** Never put it in browser JavaScript, a mobile app bundle, a desktop client, or anything else the end user can open and read. Anyone who can view the code can spend against your account.

## Where to keep the key

Read the key from the environment at call time. Never write it into source, a committed config file, or a payload example.

```plaintext
# .gitignore (commit this)
.env

# .env (never committed)
WHCC_SANDBOX_API_KEY=<YOUR_SANDBOX_KEY>
WHCC_PRODUCTION_API_KEY=<YOUR_PRODUCTION_KEY>
```

```shell
# a shell does not read .env on its own, so load it first
set -a && . ./.env && set +a

curl https://apis-stage.whcc.com/api/v1/catalog/products \
	-H "Authorization: Bearer $WHCC_SANDBOX_API_KEY"
```

Every example in these docs uses `<YOUR_API_KEY>` as a placeholder. When you copy one, substitute a variable rather than the literal key, so a pasted command never carries the credential.

- **`local development`**: A `.env` file listed in `.gitignore`, or your OS keychain.
- **`shared or deployed`**: A secret manager such as 1Password, AWS Secrets Manager, or HashiCorp Vault, injected as an environment variable at runtime. Anything shared over chat or email is a copy you can no longer account for.

> `.gitignore` only protects a file that was never committed. If `.env` is already tracked, adding it to `.gitignore` changes nothing, and the key stays in history. See [If a key is exposed](https://www.whcc.com/developer/docs/api/api-key-security/#exposure).

### Separate sandbox and production keys

Each key is bound to one account *on one host*. A sandbox key does not work against production, and a production key does not work against the sandbox. The wrong key is rejected before the request reaches the API ([Errors & Rate Limits](https://www.whcc.com/developer/docs/api/errors/#gateway-errors)).

- **`https://apis-stage.whcc.com/api`**: Sandbox key. Build and test against this host first.
- **`https://apis.whcc.com/api`**: Production key. A submission here is a real order that WHCC produces, ships, and bills you for.

Keep the two keys in different secret entries, and never let a sandbox config fall back to the production key.

### Redact the key in logs and support threads

Request logging that dumps headers captures the credential on every call. Redact the `Authorization` header at the logger, and again before pasting anything into an issue, a support thread, or a bug report:

```plaintext
Authorization: Bearer [REDACTED]
```

If you need to identify *which* key produced a request, send the `sk_` prefix and the four characters after it, never the whole value.

### Handing a key to an AI agent

Give an agent access to the key through an environment variable or secret store its tools read at call time. Never paste the key into a prompt, a chat message, or an agent instruction file. See [Build It with an Agent](https://www.whcc.com/developer/docs/api/ai-agents/index.html.md) for the full setup.

## If a key is exposed

Committed to a repository, pasted into a prompt, posted in a ticket, printed in a log someone else can read: treat them all the same way. **Assume the key is compromised and stop using it.**

> **Deleting the commit does not undo the exposure.** The key remains in git history, in every clone and fork, and in any automated scanner that already read it. Rewriting history is not a substitute for revoking the key.

Contact us and we'll revoke the exposed key and issue a replacement. Reach your WHCC representative directly, or use the Get in Touch form. WHCC handles every key change for you today. Self-service key management, where you create, rotate and revoke keys yourself, is planned.

When you report it, include:

- **`which key`**: The `sk_` prefix and the few characters after it: enough to identify the key, not enough to use it. **Never send the key itself.** A support thread is one more place it would live.
- **`when`**: When it was exposed and when you noticed, so we can tell unexpected activity apart from your own.
- **`where`**: Where it was exposed (a public repository, an agent transcript, a log shipped off-site) and whether that location is still reachable.

In the meantime, pause any automation still using the old key, so revoking it doesn't break a flow halfway through. To check for orders you didn't place, list your submissions with `GET /v1/commerce/submissions` and look for any you don't recognize.

> ## What's Next
>
> New to the WHCC API? Start with the [Quick Start](https://www.whcc.com/developer/docs/quick-start/index.html.md), which walks a print order end to end.
>
> Looking for the rest of the reference? See the [WHCC API Reference](https://www.whcc.com/developer/docs/api/index.html.md) for hosts, endpoints, and the full response bodies.
>
> Have a question about a route or your particular use case? Get in touch. We're happy to help before you build around an assumption.