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

# Production patterns

> Keep keys server-side, cache by how fast each data class moves, and pass through provenance and refusals.

Two things separate a toy integration from a production one: you keep the key out of anything a user can see, and you cache each data class on its own clock. Retries and limits link out to the pages that own them.

## Keep the key server-side

The `X-API-Key` secret belongs in your backend, an agent runtime config, or a secret manager — never anywhere a user or a model can read it.

* No key in a browser bundle, mobile app, public repo, prompt, log line, or screenshot.
* Proxy client calls through your own backend; the key never reaches the browser.
* The raw secret is shown once at creation. Store it in a secret manager. New keys come from the [dashboard](https://stockcontext.com/dashboard/keys).
* On a suspected leak, revoke the key in the dashboard and issue a new one.
* Do not cache a `401` or a quota `429` as if it were data; a fixed key or a reset window should take effect immediately.

## Cache by data class

Fundamentals change only when a new filing lands; prices change every trading day. Cache each on its own clock. These are starting points, not API contracts — tune against your traffic.

| Data                                                | Suggested cache                                 |
| --------------------------------------------------- | ----------------------------------------------- |
| `stock_search`, `stock_reference`                   | Hours to days                                   |
| `stock_financials`, `stock_overview` (fundamentals) | Until the next filing — hours to days is safe   |
| `stock_overview` valuation block (price-derived)    | Minutes to an hour during market hours          |
| `stock_prices` (snapshot / corporate actions)       | Minutes during market hours; longer after close |
| `stock_technicals`                                  | Same market cursor as the held price bars       |
| `stock_prices` (history)                            | Hours to days                                   |
| `stock_filings`, `stock_insider`, `stock_ownership` | Hours to a day                                  |

Two hooks make these self-tuning. Fundamentals responses carry `meta.published_at` and `meta.last_verified_at`, so you can tell how fresh the projection is. Price data carries its own `meta.as_of.market` clock. Key by tool plus normalized body — for example `sctx:financials:AAPL:annual:3`. Uppercase the symbol and apply defaults so an omitted `period_kind` and `annual` hit the same entry.

<Note>
  Scope cache keys per plan or tenant if different keys can see different quotas. A shared cache that ignores scope can let one tenant's requests count against another's budget.
</Note>

## Retries and limits

Wrap every call in the retry loop that retries only `429`/`5xx`, honors `Retry-After`, and caps total wait. The code is in [Errors and retries](/docs/guides/errors-and-retries). The per-plan minute and quota numbers are on [Plans and limits](/docs/reference/plans-and-limits). Track `X-Credits-Remaining` when it is present so long-running jobs can stop before they hit `quota_exhausted`.

## SEC-backed tools can be slow cold

`stock_filings`, `stock_insider`, and `stock_ownership` read SEC data and can be slow on a cold path for a heavy filer. Do not block a page render on them: run them in a background job and cache the result, since filing facts are effectively immutable once published.

## Preserve provenance and refusals

Whatever your UI shows, carry these through so the answer stays truthful:

* **The clocks.** `meta.as_of.sec` for fundamentals, `meta.as_of.market` for prices. If you present a price-derived multiple, keep its price date.
* **Provenance.** `status` (`direct` / `derived`), `provenance` (`licensed_market_data`, `computed_from_prices`, `sec_filing`), and — at `detail: "full"` — the `sources` and `accession`.
* **Refusals.** When a field has `unavailable`, show the gap and the token; never render it as `0`.
* **Coverage bounds.** `is_covered` / `ingestion_pending` on search, and the `coverage` block (`exhaustive: false`) on `stock_ownership`.

Hiding a refusal or a coverage bound makes a number look more certain than it is. Surface it.

<CardGroup cols={2}>
  <Card title="Batch workflows" icon="layers" href="/docs/guides/batch-workflows">
    Run many symbols with bounded concurrency.
  </Card>

  <Card title="Plans and limits" icon="gauge" href="/docs/reference/plans-and-limits">
    Per-plan minute limits and quotas.
  </Card>
</CardGroup>
