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

# API keys

> Store provider API keys with Pullfrog or in GitHub Actions secrets, connect several subscriptions with fallback, and route a provider through your own gateway.

Pullfrog runs on your own API key (BYOK, bring your own key) for every [supported provider](/models#supported-providers), and for [providers with no console card](/models#custom-providers) through GitHub Actions secrets. You keep your provider relationship, rate limits and billing, and pay the provider directly at its prices.

To run on a Claude, ChatGPT, Grok, Kimi or OpenCode Go plan you already pay for, see [your existing subscription](/model-access#your-existing-subscription). To skip keys entirely, see [Pullfrog Router](/billing#pullfrog-router).

## Key storage

| Where | Set it in | Scope |
| - | - | - |
| [Pullfrog secrets](#pullfrog-secrets) (recommended) | The Pullfrog console | The account, or one repository |
| [GitHub Actions secrets](#github-actions-secrets) | GitHub, then the workflow `env:` block | The workflow |

You can mix the two per provider. If a key is set in both, the workflow value wins, so a workflow can override a stored key.

### Pullfrog secrets

Pullfrog encrypts stored keys at rest, injects them into each run, and never writes them to your repository or workflow files. No workflow edits are needed.

1. Open `pullfrog.com/console/<account>` and find the **Providers** section of the **Billing** card.
2. Select the **BYOK** tab.
3. Click **Set up** on the provider's card and follow its credential instructions.

<Frame>
  <img src="https://mintcdn.com/pullfrog/klps40MoSQ5FJkiz/images/providers-byok.png?fit=max&auto=format&n=klps40MoSQ5FJkiz&q=85&s=88e152c78a28b58f9eee01a03ca80146" alt="The Providers section of the Billing card on the BYOK tab" width="1680" height="2268" data-path="images/providers-byok.png" />
</Frame>

The **Add secret** modal scopes a secret to the whole account or to one repository:

<Frame>
  <img src="https://mintcdn.com/pullfrog/klps40MoSQ5FJkiz/images/add-secret-modal.png?fit=max&auto=format&n=klps40MoSQ5FJkiz&q=85&s=e116e46fa4290813a4d04cab82b909ab" alt="Add secret modal in the Pullfrog console" width="1232" height="942" data-path="images/add-secret-modal.png" />
</Frame>

Every repository inherits the account's secrets. A repository secret with the same name overrides the account one for that repository only.

On an organization, only owners can open the **Billing** card. Repository admins manage keys for their repository in the **Secrets** section of the repository console, where inherited account secrets appear read-only:

<Frame>
  <img src="https://mintcdn.com/pullfrog/klps40MoSQ5FJkiz/images/repo-secrets-card.png?fit=max&auto=format&n=klps40MoSQ5FJkiz&q=85&s=8224d451de011778f626c4c1244bc224" alt="Secrets card on the repo console" width="1648" height="1112" data-path="images/repo-secrets-card.png" />
</Frame>

### GitHub Actions secrets

Keep keys in GitHub when you already rotate secrets there. Pullfrog reads them from the workflow `env:` block.

1. Add the secret in GitHub, at the organization (`github.com/organizations/<org>/settings/secrets/actions`, **New organization secret**) or the repository (`github.com/<org>/<repo>/settings/secrets/actions`, **New repository secret**).
2. Map it into `pullfrog.yml`:

   ```diff theme={null}
    jobs:
      pullfrog:
        runs-on: ubuntu-latest
        steps:
          - name: Run agent
            uses: pullfrog/pullfrog@v0
            with:
              prompt: ${{ inputs.prompt }}
   +        env:
   +          ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
   ```

Any variable in `env:` reaches the agent, so a provider with no console card runs from a GitHub Actions secret too. See [custom providers](/models#custom-providers).

## Cloud providers and custom endpoints

These routes are BYOK only and have their own setup pages:

| Route | Use it for |
| - | - |
| [Amazon Bedrock](/bedrock) | Inference through your AWS account, with pinned model IDs |
| [Google Vertex AI](/vertex) | Inference through your Google Cloud project, with pinned model IDs |
| [Azure OpenAI](/azure) | Your Azure deployments, billed to your Azure subscription |
| [OpenAI-compatible endpoints](/openai-compatible) | A LiteLLM proxy, a self-hosted vLLM server, or any gateway that speaks chat completions |

## Multiple subscriptions and fallback

Connect several Claude, Codex or Grok subscriptions by running the provider's auth command again. Choose **Add another** to keep the existing connections as fallbacks, or **Replace** to swap one out once the new connection succeeds. The account that signs in decides the result, and the CLI reports it: `added`, `replaced`, or `reconnected` when the sign-in was an account already connected. A browser signs in as the account it already holds, so adding a second account takes a signed-out browser or a private window.

```bash theme={null}
npx pullfrog auth claude --org my-org
npx pullfrog auth codex --repo my-org/my-repo
npx pullfrog auth grok --org my-org
```

Each subscription card lists its connected accounts; Claude connections show the end of the setup token, and Codex and Grok connections show the account email when available. The pencil removes a connection or copies the command to add another. After a run checks a connection, its card shows **Rejected** if the provider refused it, or **Limit reached** with the reset time when the provider gives one.

Before the agent starts, Pullfrog tries the credentials for the run's model and provider in this order:

1. Subscriptions: the workflow's, then the repository's, then the account's, then shared personal ones
2. API keys: the workflow's, then the repository's, then the account's

Within a scope, the most recently connected subscription goes first. A rejected or exhausted credential moves the run to the next one, so a fallback to an API key can incur API charges. If a provider cannot answer the check, Pullfrog keeps the current credential. Once the agent has started, Pullfrog does not switch credentials or models.

<Note>
  Checks for some providers send a small inference request. A passing check does not reserve quota or guarantee the whole run fits within the limit.
</Note>

### Personal subscriptions on organization repositories

The owner of a personal account can share one of its subscriptions with an organization or repository they also manage:

```bash theme={null}
npx pullfrog auth list --org my-username
npx pullfrog auth share CREDENTIAL_ID --from my-username --repo my-org/my-repo
npx pullfrog auth unshare CREDENTIAL_ID --from my-username --repo my-org/my-repo
```

The list prints a binding ID for `auth remove`, a credential ID for `auth share` and `auth unshare`, and each connection's status: **Rejected**, **Limit reached** with its reset time, or `-` when the last check passed. Removing the connection from the personal account revokes its shares. Nothing is shared automatically because someone triggered a run.

## Gateways and proxies

Route a provider's requests through your own host, such as a LiteLLM proxy, a corporate egress proxy or an AI gateway, while keeping your normal model selection. Set the base URL under **Set up a proxy or gateway** on the provider's setup card, or in your workflow `env:`:

| Provider | Variable |
| - | - |
| Anthropic | `ANTHROPIC_BASE_URL` |
| OpenAI | `OPENAI_BASE_URL` |

Put only the host in the base URL; a credential embedded in it is not treated as one. Pullfrog skips its pre-run credential check for a gateway, so a gateway that refuses the credential reports its own error in the run.

<Frame>
  <img src="https://mintcdn.com/pullfrog/klps40MoSQ5FJkiz/images/gateway-setup.png?fit=max&auto=format&n=klps40MoSQ5FJkiz&q=85&s=900aa1d870a605db8627f50c3895ff76" alt="The Configure Anthropic dialog with Set up a proxy or gateway expanded to ANTHROPIC_BASE_URL" width="1104" height="988" data-path="images/gateway-setup.png" />
</Frame>

Other providers take other routes. [Azure OpenAI](/azure) builds its endpoint from `AZURE_RESOURCE_NAME`, and a gateway with its own model list belongs on [OpenAI-compatible endpoints](/openai-compatible).

### Anthropic

Anthropic models run through Claude Code, which honors `ANTHROPIC_BASE_URL` natively and talks to the gateway in Anthropic's own format, so prompt caching and extended thinking survive the hop.

```yaml theme={null}
env:
  ANTHROPIC_BASE_URL: https://gateway.internal.example.com
  ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
```

Pick the credential variable by the header your gateway reads. The `ANTHROPIC_API_KEY` variable is sent as `x-api-key`, and `ANTHROPIC_AUTH_TOKEN` as `Authorization: Bearer`. A gateway that reads the other header answers `401`.

```yaml theme={null}
env:
  ANTHROPIC_BASE_URL: https://gateway.internal.example.com
  ANTHROPIC_AUTH_TOKEN: ${{ secrets.GATEWAY_TOKEN }}
```

This route serves Claude models only. Anthropic [doesn't support routing Claude Code to non-Claude models through a gateway](https://code.claude.com/docs/en/llm-gateway), so use [OpenAI-compatible endpoints](/openai-compatible) for a provider's `/anthropic` endpoint that serves its own models.

### OpenAI

The `OPENAI_BASE_URL` variable re-points the OpenAI provider, which speaks the **Responses API** (`POST /v1/responses`). Point it at a gateway that serves that endpoint.

```yaml theme={null}
env:
  OPENAI_BASE_URL: https://gateway.internal.example.com/v1
  OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
```

Most third-party gateways speak the older Chat Completions API (`POST /v1/chat/completions`), which is what "OpenAI-compatible" usually means. For one of those, use [OpenAI-compatible endpoints](/openai-compatible) instead.

## Troubleshooting

### "Missing API key" error in GitHub Actions

The agent found no valid key at runtime. Check, in order:

1. The selected model's env var is set in Pullfrog secrets or in a workflow `env:` mapping.
2. The secret name matches the provider's env var exactly: `ANTHROPIC_API_KEY`, not `CLAUDE_API_KEY`.
3. A GitHub secret is mapped in the `env:` block of `pullfrog.yml`. GitHub Actions injects only what the workflow lists.

### "Missing API key" warning in the console

The console found no stored key for the selected model. Add one under **Providers** on the **Billing** card, or switch to a model whose key you already have.


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