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

# Managing Secrets

> Store, rotate, and inject API credentials without exposing them to agents.

# Managing Secrets

This guide covers creating encrypted credentials, configuring injection routes, and rotating keys — all without redeploying agent containers.

## Prerequisites

* Tenant-level API key (secrets require tenant auth)
* API credentials to store (OpenAI key, Anthropic key, etc.)

## Creating a Secret

```typescript theme={null}
const response = await fetch("https://api.steward.fi/secrets", {
  method: "POST",
  headers: {
    "X-Steward-Key": "your-tenant-key",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    name: "openai-prod",
    value: "sk-proj-abc123...",
    description: "Production OpenAI API key",
    expiresAt: "2027-01-01T00:00:00Z", // optional
  }),
});

const { data } = await response.json();
console.log(data.id);   // "550e8400-..."
console.log(data.name); // "openai-prod"
// Note: the value is NEVER returned in responses
```

## Creating a Route

Routes tell the proxy how to inject credentials when an agent makes a request:

```typescript theme={null}
// Route for OpenAI
await fetch("https://api.steward.fi/secrets/routes", {
  method: "POST",
  headers: {
    "X-Steward-Key": "your-tenant-key",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    secretId: "550e8400-...", // the secret ID from above
    hostPattern: "api.openai.com",
    pathPattern: "/*",
    injectAs: "header",
    injectKey: "Authorization",
    injectFormat: "Bearer {value}",
    priority: 0,
    enabled: true,
  }),
});
```

### Common Route Examples

<Accordion title="OpenAI">
  ```json theme={null}
  {
    "secretId": "openai-secret-id",
    "hostPattern": "api.openai.com",
    "pathPattern": "/*",
    "injectAs": "header",
    "injectKey": "Authorization",
    "injectFormat": "Bearer {value}"
  }
  ```
</Accordion>

<Accordion title="Anthropic">
  ```json theme={null}
  {
    "secretId": "anthropic-secret-id",
    "hostPattern": "api.anthropic.com",
    "pathPattern": "/*",
    "injectAs": "header",
    "injectKey": "x-api-key",
    "injectFormat": "{value}"
  }
  ```
</Accordion>

<Accordion title="Birdeye (Custom Header)">
  ```json theme={null}
  {
    "secretId": "birdeye-secret-id",
    "hostPattern": "public-api.birdeye.so",
    "pathPattern": "/defi/*",
    "injectAs": "header",
    "injectKey": "X-API-KEY",
    "injectFormat": "{value}"
  }
  ```
</Accordion>

<Accordion title="GitHub (Fine-Grained PAT)">
  ```json theme={null}
  {
    "secretId": "github-pat-id",
    "hostPattern": "api.github.com",
    "pathPattern": "/repos/acme/widgets/issues/1/comments",
    "method": "POST",
    "injectAs": "header",
    "injectKey": "Authorization",
    "injectFormat": "Bearer {value}"
  }
  ```
</Accordion>

<Note>
  Credentials are injected as request **headers** only. Query-parameter and
  request-body injection are not supported: upstream responses can reflect query
  strings and bodies, which would risk leaking the injected credential back to
  the agent.
</Note>

## GitHub Fine-Grained Tokens

GitHub is an allowlisted credential host, but routes for `api.github.com` are
held to an extra **narrowness** standard so a single token can only be attached
to the exact endpoint you intend:

* The route **must** specify an explicit `method` (no wildcard `*`).
* The `pathPattern` **must** have at least two path segments
  (`/repos/acme/widgets`, not `/` or `/user`).

A route that violates either rule is rejected at creation time.

### 1. Mint a fine-grained PAT

Create a **fine-grained personal access token** in GitHub with the minimum
scope for the job:

* **Resource owner / repositories:** select only the specific repositories the
  agent needs (for example `acme/widgets`), never "All repositories."
* **Permissions:** grant only what the endpoint requires (for example
  *Issues: Read and write* for posting issue comments). Leave everything else
  at *No access*.
* **Expiration:** set a short expiration and rotate on schedule.

### 2. Store the token as a secret

```bash theme={null}
curl -X POST https://api.steward.fi/secrets \
  -H "X-Steward-Key: your-tenant-key" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "github-acme-widgets",
    "value": "github_pat_...",
    "description": "Fine-grained PAT: acme/widgets issues read+write"
  }'
```

### 3. Create a narrow route

Scope the route to one method and one deep path. GitHub accepts both
`Authorization: Bearer <token>` and `Authorization: token <token>`; either
`injectFormat` works.

```bash theme={null}
curl -X POST https://api.steward.fi/secrets/routes \
  -H "X-Steward-Key: your-tenant-key" \
  -H "Content-Type: application/json" \
  -d '{
    "secretId": "github-acme-widgets-id",
    "agentId": "your-agent-id",
    "hostPattern": "api.github.com",
    "pathPattern": "/repos/acme/widgets/issues/1/comments",
    "method": "POST",
    "injectAs": "header",
    "injectKey": "Authorization",
    "injectFormat": "Bearer {value}"
  }'
```

### 4. Call through the proxy

The agent calls the `github` alias with its own agent token. The proxy matches
the route, injects the PAT as the `Authorization` header, and forwards the
request. The agent never sees the token.

```bash theme={null}
curl -X POST https://proxy.steward.fi/github/repos/acme/widgets/issues/1/comments \
  -H "Authorization: Bearer <agent-token>" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{ "body": "posted by the agent via steward" }'
```

<Note>
  Mutating proxy requests (POST, PUT, PATCH, DELETE) require an
  `Idempotency-Key` header.
</Note>

## Listing Secrets

```bash theme={null}
curl https://api.steward.fi/secrets \
  -H "X-Steward-Key: your-key"
```

```json theme={null}
{
  "ok": true,
  "data": [
    {
      "id": "550e8400-...",
      "name": "openai-prod",
      "description": "Production OpenAI API key",
      "version": 1,
      "createdAt": "2026-03-26T12:00:00Z"
    },
    {
      "id": "660f9500-...",
      "name": "anthropic-prod",
      "description": "Anthropic production key",
      "version": 2,
      "createdAt": "2026-03-20T10:00:00Z"
    }
  ]
}
```

## Rotating a Secret

When you need to update a credential (e.g., API key rotation), use the rotate endpoint:

```bash theme={null}
curl -X POST https://api.steward.fi/secrets/550e8400-.../rotate \
  -H "X-Steward-Key: your-key" \
  -H "Content-Type: application/json" \
  -d '{ "value": "sk-proj-new-key-xyz..." }'
```

This:

1. Creates a new encrypted version of the secret
2. Routes automatically use the latest version
3. **No container redeployment needed** — agents keep making the same proxy calls

## Deleting a Secret

```bash theme={null}
curl -X DELETE https://api.steward.fi/secrets/550e8400-... \
  -H "X-Steward-Key: your-key"
```

<Warning>
  Deleting a secret will cause proxy requests that depend on it to fail with 403. Make sure no active routes reference the secret before deletion.
</Warning>

## Managing Routes

### List Routes

```bash theme={null}
curl https://api.steward.fi/secrets/routes \
  -H "X-Steward-Key: your-key"
```

### Update a Route

```bash theme={null}
curl -X PUT https://api.steward.fi/secrets/routes/route-id \
  -H "X-Steward-Key: your-key" \
  -H "Content-Type: application/json" \
  -d '{ "enabled": false }'
```

### Delete a Route

```bash theme={null}
curl -X DELETE https://api.steward.fi/secrets/routes/route-id \
  -H "X-Steward-Key: your-key"
```

## Priority-Based Routing

When multiple routes match a request, the one with the highest `priority` wins:

```typescript theme={null}
// Trading API gets a privileged credential (priority 10)
await createRoute({
  secretId: "trading-api-prod",
  hostPattern: "api.example.com",
  pathPattern: "/v2/trading/*",
  priority: 10,
  // ...
});

// Everything else gets read-only credential (priority 0)
await createRoute({
  secretId: "api-read-only",
  hostPattern: "api.example.com",
  pathPattern: "/*",
  priority: 0,
  // ...
});
```

## Related

* [Secret Vault Concepts](/concepts/secret-vault) — How encryption works
* [Proxy Gateway](/concepts/proxy-gateway) — How injection works in the proxy
* [Secrets API](/api-reference/secrets) — Full REST API reference
* [Routes API](/api-reference/routes) — Route management API
