# Verifying the integration

Do not report success because the code compiles. Verify in this order and stop at
the first failure.

## 1. Is the base URL right?

The single most common failure. Check per SDK:

| SDK | Correct | Wrong |
|---|---|---|
| OpenAI | `https://www.spendline.ai/v1` | `https://www.spendline.ai` |
| Anthropic | `https://www.spendline.ai` | `https://www.spendline.ai/v1` |

A wrong Anthropic base URL produces requests to `/v1/v1/messages` → 404.

## 2. Make one real call per provider

One call per provider the app actually uses, and both streaming and
non-streaming where the app uses both. The Responses API is non-streaming only.

```bash
curl -i https://www.spendline.ai/v1/chat/completions \
  -H "Authorization: Bearer $OPENAI_API_KEY" \
  -H "x-spendline-key: $SPENDLINE_API_KEY" \
  -H "x-agent-id: integration-smoke-test" \
  -H "x-customer-id: verification-probe" \
  -H 'x-spendline-tags: {"team":"platform"}' \
  -H "Content-Type: application/json" \
  -d '{"model":"gpt-5.6","messages":[{"role":"user","content":"say ok"}],"max_tokens":5}'
```

A `200` proves reachability and auth. It does **not** prove attribution.

## 3. Prove the call was recorded and attributed

This is the step people skip. A 200 with a null `customer_id` is a failed
integration that looks like a success.

```bash
# most recent calls; filter to the probe you just sent
curl -s "https://www.spendline.ai/api/calls?agent=integration-smoke-test" \
  -H "x-spendline-key: $SPENDLINE_API_KEY"
```

`/api/calls` is paginated with `?page=N` (fixed page size) and filterable with
`customer`, `agent`, `model`, `status`, `timeRange`, `sourceRoute`, `success`,
`search` and `tags` (a JSON object). There is no `limit` parameter.

Confirm the most recent row has:

- your `agent_id`,
- the **correct** `customer_id` (not null, not a placeholder),
- a non-zero `cost_usd`,
- the model you requested (or the reroute target, if a rule applied).

```bash
curl -s https://www.spendline.ai/api/stats/summary \
  -H "x-spendline-key: $SPENDLINE_API_KEY"
```

## 4. Prove customer attribution actually varies

Send two calls with **different** `x-customer-id` values, then confirm two
distinct customers appear:

```bash
curl -s https://www.spendline.ai/api/budgets/scopes \
  -H "x-spendline-key: $SPENDLINE_API_KEY"
```

If `customers` contains one entry after two different ids, `x-customer-id` is
pinned in `default_headers` instead of being passed per request. Fix it, see
[attribution](https://www.spendline.ai/agents/attribution.md).

## 5. Prove enforcement works

Only with the human's agreement, since it blocks real traffic: create a tiny
budget on a throwaway `agent_id`, send a call with that `x-agent-id`, and confirm
a **402**. Then remove the budget.

If you cannot test this, say so in your report rather than claiming enforcement
is verified.

## 6. Confirm fallback behaviour

Check the code, not the network:

- 5xx / timeout / network error → retries once against the provider. **Correct.**
- 402 or 403 → surfaces the error. **Must not** fall back.
- 401 → surfaces the error. **Must not** fall back.

## Report template

```
Spendline integration report

Call sites found:        N
Repointed:              N   (list files)
Left as-is:             N   (unsupported shape, embeddings/images/audio)
Needs a decision:       N   (list, with the question)

Env vars added:         SPENDLINE_URL, SPENDLINE_API_KEY, SPENDLINE_ENABLED

Verification
  openai    non-streaming 200 / streaming 200 / recorded yes / customer_id correct
  anthropic non-streaming 200 / streaming 200 / recorded yes / customer_id correct
  attribution varies across customers: yes
  enforcement 402 observed: yes | not tested (reason)
  fallback: 5xx only, confirmed by reading <file:line>
```

Report honestly. "Not tested" is a valid entry; a false "verified" is not.
