Raxx · internal docs

internal · gated ↑ index

Rotation SOP — Alpaca Paper Trading API Keys

Mode: operator-assisted Last validated: 2026-04-24 UTC Validation method: read-only-docs (sandbox-rotation safe — paper account has no real-money impact) Average duration: 5m Required role: ops

Applies to: ALPACA_PAPER_API_KEY_ID, ALPACA_PAPER_API_SECRET_KEY (and any per-environment paper keys, e.g., dev/staging variants).

Important gotcha surfaced during research: Alpaca's "Reset Paper Account" button on the dashboard also regenerates the API key/secret. If an operator clicks "Reset" intending to clear simulated balance, they will silently invalidate the running paper credentials. The community has requested this behavior change for years; it is unresolved as of 2026-04-24. Always rotate via the explicit "Regenerate" / "View" path on the API Keys panel, never via the Reset button.

When to run

Prerequisites

Steps

1. Pre-rotation checks

# Confirm current key still works against the paper endpoint
curl -sS -H "APCA-API-KEY-ID: $CURRENT_KEY_ID" \
     -H "APCA-API-SECRET-KEY: $CURRENT_SECRET" \
     https://paper-api.alpaca.markets/v2/account | jq '.status'
# Expect: "ACTIVE"

Snapshot any open paper orders/positions in case a downstream restart cancels them.

2. Generate the new credential

There is no Alpaca API to rotate keys programmatically. The dashboard is the only path.

  1. Navigate to https://app.alpaca.markets/paper/dashboard/overview.
  2. Confirm the environment switcher (upper-left) shows Paper Trading.
  3. In the right sidebar, locate the API Keys section.
  4. Click "View" on the existing key OR "Regenerate" if the dashboard offers it (UI varies by account vintage).
  5. If only "Generate New Keys" is available, that creates a fresh pair and invalidates the old keys atomically.
  6. Copy both Key ID and Secret Key immediately. The Secret is shown once.

3. Validate the new credential

NEW_KEY_ID="..."
NEW_SECRET="..."
curl -sS -H "APCA-API-KEY-ID: $NEW_KEY_ID" \
     -H "APCA-API-SECRET-KEY: $NEW_SECRET" \
     https://paper-api.alpaca.markets/v2/account | jq '{status, account_number, buying_power}'
# Expect: status = "ACTIVE", account_number unchanged from pre-rotation snapshot.

4. Store in Infisical

infisical secrets set ALPACA_PAPER_API_KEY_ID="$NEW_KEY_ID" \
  --projectId="$INFISICAL_PROJECT_ID" --env=prod
infisical secrets set ALPACA_PAPER_API_SECRET_KEY="$NEW_SECRET" \
  --projectId="$INFISICAL_PROJECT_ID" --env=prod

5. Propagate to downstream consumers

Consumer How
Raptor (raxx-api-prod, raxx-api-staging) heroku config:set ALPACA_PAPER_API_KEY_ID=... ALPACA_PAPER_API_SECRET_KEY=... -a raxx-api-prod
Local dev environments DM operator via Slack D0AJ7K184TV to update local .env
GitHub Actions (integration tests against paper) gh secret set ALPACA_PAPER_API_KEY_ID -b ...; gh secret set ALPACA_PAPER_API_SECRET_KEY -b ...

6. Verify downstream

# Hit the Raptor endpoint that proxies Alpaca paper /v2/account
curl -sS https://api.raxx.app/api/trading/account | jq '.alpaca_status'
# Expect: "ACTIVE" (or whatever wrapper the Raptor route emits on success)

Place a paper test order via the Raptor API and verify it appears in the Alpaca paper dashboard:

curl -sS -X POST https://api.raxx.app/api/trading/orders \
  -H "Content-Type: application/json" \
  -d '{"symbol":"AAPL","qty":1,"side":"buy","type":"market","time_in_force":"day","mode":"paper"}'
# Confirm order ID appears in https://app.alpaca.markets/paper/dashboard/orders

7. Revoke the old credential

The Alpaca dashboard's "Generate New Keys" / "Regenerate" action already invalidates the old key pair atomically — no separate revoke step is needed. Confirm:

curl -sS -o /dev/null -w "%{http_code}\n" \
     -H "APCA-API-KEY-ID: $OLD_KEY_ID" \
     -H "APCA-API-SECRET-KEY: $OLD_SECRET" \
     https://paper-api.alpaca.markets/v2/account
# Expect: 401 or 403

8. Audit log entry

action: secret.rotate.completed
actor: <admin_id>
context: {"secret_name": "ALPACA_PAPER_API_KEY_ID", "method": "operator-assisted-dashboard", "rotated_at": "..."}

Rollback

No rollback exists. Once "Generate New Keys" is clicked the old keys are dead. Options:

  1. If the new keys are broken or unusable, regenerate again (each click invalidates the previous attempt).
  2. If propagation breaks downstream, revert the Heroku config vars to the previous value from Infisical history — but those will not authenticate against Alpaca. The only correct fix is to redo step 5+6 with the current live keys.

Vendor doc references

Known gotchas