Latch / Docs
get started

Quickstart

Make your first proxied call in about five minutes.

By the end of this you will have an API key that an agent can use, without the agent ever holding the key.

We will use OpenAI as the upstream. Any HTTP API works the same way.

1. Store the credential as a Secret

In the dashboard, go to Secrets and create one:

Field Value
Name OpenAI production
Credential your real sk-… key
Inject as Header
Header name Authorization
Prefix Bearer

Latch encrypts the credential at rest and never returns it, not to you, not to the dashboard, not to a caller. From here on you refer to it by name.

2. Mint a Latch

Go to Latches and create one against that secret:

Field Value
Name Support bot
Secret OpenAI production
Upstream https://api.openai.com

You get an access token, lat_…. Copy it now, it is shown once.

This token is what the agent holds. It is not the OpenAI key, it cannot be turned back into the OpenAI key, and revoking it does not require rotating the OpenAI key.

3. Give it a policy

Right now the latch forwards anything. Add two filters in the pipeline editor:

[
  { "type": "method", "name": "No deletes", "allowed": ["GET", "POST"] },
  { "type": "endpoint", "name": "Completions only", "mode": "allowlist",
    "patterns": ["/v1/chat/completions"] }
]

The pipeline runs in order and the first filter to deny wins. See the filter reference for all 13 types, including rate limits, body assertions, time windows, and daily spend caps.

4. Call it

Point your client at Latch instead of the upstream, and use the latch token instead of the key. Everything else stays the same.

curl https://onlatch.com/proxy/v1/chat/completions \
  -H "Authorization: Bearer lat_9f3c…" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gpt-4o-mini",
    "messages": [{ "role": "user", "content": "hello" }]
  }'

Latch evaluates the pipeline, injects the real OpenAI key, forwards the request, and returns OpenAI's response to you verbatim.

The path after /proxy/ is passed straight through, so /proxy/v1/chat/completions reaches https://api.openai.com/v1/chat/completions.

5. Watch it deny

Now try something the policy forbids:

curl https://onlatch.com/proxy/v1/embeddings \
  -H "Authorization: Bearer lat_9f3c…" \
  -H "Content-Type: application/json" \
  -d '{ "model": "text-embedding-3-small", "input": "hello" }'
{
  "error": "Request denied by policy",
  "requestId": "req_4a1f2c",
  "latchId": "lnk_9f3c1a2b",
  "deniedBy": "Completions only",
  "reason": "/v1/embeddings not in allowlist"
}

403. The request never reached OpenAI, and the key was never used. deniedBy names the filter that stopped it, so the agent (or you) can tell exactly what it did wrong.

Every call, allowed or denied, lands in Activity with the full filter trace.

Using it from an SDK

Most clients let you override the base URL, which is all this takes:

from openai import OpenAI

client = OpenAI(
    api_key="lat_9f3c…",                    # the latch, not your OpenAI key
    base_url="https://onlatch.com/proxy",
)

client.chat.completions.create(
    model="gpt-4o-mini",
    messages=[{"role": "user", "content": "hello"}],
)

The agent has no idea Latch is there. It just has less power than it thinks.

Next