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

# 0009. Venue API credentials are derived at startup and held in memory

# 0009. Venue API credentials are derived at startup and held in memory

* **Status:** Proposed
* **Date:** 2026-09-30

## Context

Phase 2 reads the account: open orders, cash and the User WS need Polymarket CLOB API
credentials (key, secret, passphrase). They are created or derived through L1 auth: the
signer signs a `ClobAuth` message and the CLOB returns the credentials. With a Session
Key, the credentials belong to the Session Key.

The Phase 0 `.env.example` named the signer `POLYMARKET_PRIVATE_KEY`, described it as the
key that controls the account, and suggested saving derived credentials back into `.env`.
The security review found (F1) that the name invites putting the owner key on the host,
and (F8) that the signer key has no use on the geoblocked development server. Every copy
of a credential on disk is one more place it can leak from.

## Decision

* The signer is `POLYMARKET_SESSION_KEY`: a CLOB-scoped Polymarket Session Key for the
  Deposit Wallet in `POLYMARKET_WALLET_ADDRESS`. The owner key never goes into the app.
* If `POLYMARKET_CLOB_API_KEY`, `_SECRET` and `_PASSPHRASE` are set, the app uses them.
  Otherwise a credential actor in `venue/polymarket` derives them through L1 auth at
  startup and holds them in memory only. They are never written to `.env`, SQLite, logs,
  errors, API responses or WS frames, and they are derived again at each start.
* The old name `POLYMARKET_PRIVATE_KEY` is refused at startup with a message to rename it.
  The loader does not read it as a fallback.
* Optional `POLYMARKET_OWNER_ADDRESS` (public): the loader refuses to start when the
  signer's address equals it (F1).
* The credential actor is the single source of the credential state (PLAN §3.7). It
  publishes `core.CredentialStatus` (`none`, `pending`, `ready`, `failed` with a fixed
  reason code) on `core.TopicCredentialStatus`; the browser sees it in
  `AccountSummary.credentials`.
* Without credentials, Data API reads (positions, activity, P\&L) still work from the
  wallet address. Open orders, cash and the User WS report `credentials_unavailable`
  (503).
* The signer key is not configured on the geoblocked development server (F8). Verification
  there uses the fake venue and the golden vectors; the user verifies with real
  credentials from a permitted location.

## Consequences

* No credential file to protect, back up or rotate besides the Session Key itself.
  Rotating the key rotates the derived credentials with it.
* Each start makes one L1 request before account data that needs credentials is
  available. While it runs the state is `pending`; if it fails the state is `failed` and
  those endpoints answer 503 until a later attempt succeeds. The retry schedule is defined
  by implementation.
* A user upgrading from Phase 1 with `POLYMARKET_PRIVATE_KEY` in `.env` must rename it
  before the app starts. This is deliberate: renaming is the moment to check that the
  value is a Session Key and not the owner key.
* Configured `POLYMARKET_CLOB_*` values must belong to the configured Session Key. After a
  key rotation they must be cleared or replaced.
* The in-memory credentials still sit in process memory; crash dumps stay disabled
  (secrets and logging policy §6).

## Alternatives considered

* **Derive once and save the credentials to `.env` or SQLite.** Rejected. It adds a
  second secret at rest and a copy that outlives a key rotation, and SQLite holds no
  secret columns by policy.
* **Accept `POLYMARKET_PRIVATE_KEY` as an alias.** Rejected. The name does not say which
  key belongs there, and a silent alias is a fallback path.
* **Require the CLOB credentials in the environment.** Rejected. The user would have to
  run L1 auth by hand, and the credentials would be stored beside the key that can derive
  them anyway.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.