# Quickstart: your first Chat Completion

Run Pointsman locally, issue a virtual key, and make a real provider request. This
is an evaluation setup. Read the [deployment guide](../how-to/deploy.md) before
exposing the stack to other users.

Prefer a trial without model-provider credentials? Use the [mock-provider walkthrough](mock-provider.md).

## 1. Prepare the environment

Install Docker with Compose **2.24 or newer**, `curl`, `jq` and `openssl`. You need
an OpenAI API key for this walkthrough; requests incur provider charges. Leave time
for the first image build and the roughly 90-MB embedding-model download.

```bash
git clone https://github.com/srinivas-reddy-gouru/pointsman.git
cd pointsman
cp docker/.env.example docker/.env
openssl rand -hex 32
```

Edit `docker/.env`, setting these existing entries. Paste the generated hex string
as the pepper and choose your own admin password:

```dotenv
POINTSMAN_AUTH_PEPPER=<paste-the-generated-value>
POINTSMAN_KEY_ENVIRONMENT=test
POINTSMAN_ADMIN_USERNAME=admin
POINTSMAN_ADMIN_PASSWORD=<choose-a-long-password>
OPENAI_API_KEY=<your-openai-api-key>
ANTHROPIC_API_KEY=dummy-key
```

The current bootstrap initializes both provider clients. `dummy-key` satisfies the
unused Anthropic client's startup check for this OpenAI-only local trial; Anthropic
requests will fail until you configure a real credential. Keep requests explicitly
on `gpt-4o-mini` for this walkthrough. Placeholder credentials are not a production
configuration.

Keep the pepper stable across restarts and back it up with your secrets: changing
it invalidates existing key hashes. Do not commit `docker/.env`. Shell-exported
variables override values in the file during Compose interpolation; unset stale
exports if the running settings differ from what you edited.

## 2. Start and check readiness

From the repository root:

```bash
docker compose --env-file docker/.env -f docker/docker-compose.yml up -d --build
docker compose --env-file docker/.env -f docker/docker-compose.yml ps
curl --fail --show-error http://localhost:8080/actuator/health/readiness
```

Repeat the readiness request until it returns a successful HTTP response. If
startup fails, inspect the logs instead of waiting indefinitely:

```bash
docker compose --env-file docker/.env -f docker/docker-compose.yml logs --tail=100 gateway
```

The gateway uses port **8080** and the dashboard uses **3001**. The base Compose file
publishes these application ports on the Docker host; it keeps the backing-service
ports inside the Compose network. Use a trusted local machine for this walkthrough.
The dev overlay is only needed to access
backing services from the host, and publishes those additional ports on loopback.

## 3. Create an organization and a virtual key

These commands use the bootstrap admin `admin`. `curl` prompts for the password you
chose in step 1. The provider key stays in the gateway; your application receives
a separate revocable virtual key.

```bash
ORG_ID=$(curl --fail-with-body --silent --show-error --user admin \
  -H 'Content-Type: application/json' \
  -d '{"name":"my-team"}' \
  http://localhost:8080/admin/organizations | jq -er '.id')

KEY=$(curl --fail-with-body --silent --show-error --user admin \
  -H 'Content-Type: application/json' \
  -d '{"label":"first-app","kind":"service"}' \
  "http://localhost:8080/admin/organizations/$ORG_ID/keys" | jq -er '.key')
```

Check each command succeeded before continuing. The complete key is returned only
once; the server stores a keyed hash. `kind: service` means the key belongs to the
organization. [Key ownership and budgets →](../how-to/issue-keys-and-set-budgets.md)

## 4. Send a completion

```bash
curl --fail-with-body -i http://localhost:8080/v1/chat/completions \
  -H "Authorization: Bearer $KEY" \
  -H 'Content-Type: application/json' \
  -d '{"model":"gpt-4o-mini","max_tokens":64,"temperature":0,"messages":[{"role":"user","content":"Explain what an AI gateway does in one sentence."}]}'
```

Expect an OpenAI-shaped Chat Completion response. Inspect `X-Request-ID`,
`X-Served-Provider`, `X-Provider-Model`, `X-Cache` and `X-Cache-Semantic` to see what
happened. Their exact values depend on the selected model and cache state; the
[header reference](../reference/response-headers.md) explains the conditions.

Repeat the identical request to try the exact cache. An eligible stored response
can produce `X-Cache: HIT-L1`, avoiding another provider call. Cache eligibility,
store completion and output guardrails still apply; a paraphrase is not guaranteed
to hit the semantic tier. `temperature: 0` explicitly requests deterministic
sampling. [Cache behavior and tuning →](../semantic-cache.md)

## 5. Open the dashboard and choose a next step

Open [localhost:3001](http://localhost:3001) and log in with the same admin account.
Follow the [dashboard tour with screenshots](dashboard.md) to understand providers,
routing groups, Configuration Studio, Canvas and request investigation.
Inspect the provider/model catalog and request usage, then:

- [Issue a key with a budget](../how-to/issue-keys-and-set-budgets.md).
- [Add another provider](../how-to/add-a-provider-and-a-model.md).
- [Split traffic between models](../how-to/split-traffic-between-models.md).
- [Turn on outcome learning](../how-to/turn-on-outcome-learning.md) when you have feedback to provide.

## Troubleshooting and stopping

| Symptom | Check |
|---|---|
| Compose refuses the pepper or environment | Set the required entries and use `--env-file docker/.env` on every command. |
| A provider client refuses startup | The bootstrap requires both credential fields; see the trial-only placeholder above. |
| Readiness never succeeds | Inspect gateway and backing-service logs; check model-download access and available Docker memory. |
| Chat returns 401 | Use the virtual key, not the provider key or admin password. Check the key's environment. |
| Chat returns 400 | Check the [supported controls](../reference/compatibility.md). |
| Provider authentication fails | Confirm the provider credential and the model/provider being requested. |
| Changed admin password has no effect | Bootstrap seeds only an empty admin table; editing the environment does not reset an existing account. |

```bash
docker compose --env-file docker/.env -f docker/docker-compose.yml down
```

This stops the stack while retaining named volumes. Keep those volumes and the
same pepper if you want existing keys and data to survive the next start.

## See routing learn on a controlled demo

Once the quickstart works, the included demo can show the mechanism with three
fixture providers: fast/good, slow/good and fast/poor. It sends requests and feedback,
then reads the gateway's own learned beliefs. It is not a benchmark of real-model
answer quality or savings. First-build/download time is separate: one recorded clean
rehearsal took about seven minutes to become ready, so a ten-minute total setup is a
goal to test, not a launch promise.

Run this on your disposable evaluation stack. The script temporarily restarts the
gateway with disclosed demo settings. Set the same admin credentials you chose in
`docker/.env` (use your shell's private input for the password), then run:

```bash
export POINTSMAN_ADMIN_USERNAME=admin
read -r -s -p 'Pointsman admin password: ' POINTSMAN_ADMIN_PASSWORD; printf '\n'
export POINTSMAN_ADMIN_PASSWORD
bash scripts/demo-learning.sh
unset POINTSMAN_ADMIN_PASSWORD
```

The input example is for Bash. The script reads Compose settings from
`docker/.env`. Keep its per-checkpoint output and final verdict: seeing traffic pass
is not the same as seeing the arms separate. This demo is an operator-run traffic
test. The packaged demo passed on the qualified release candidate; its evidence is
recorded in [launch status](../release-status.md). Running it yourself illustrates
mechanics on your evaluation stack and does not establish real-model quality or savings.

The [dashboard setup recipes](dashboard.md#choose-a-setup-recipe) explain role boundaries, credential types, exact recorded-request verification, shared budgets and optional adaptive routing.
