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

# Quickstart

> Get your first verified coordinate in under a minute.

Kviria needs three things per call: the user's words, their current
anchor, and (from turn two on) the state Kviria handed you back.
Your wallet is your account — a CAIP-122 sign-in header, no key to
provision.

## 1. First call — raw transcript

Build a sign-in for your wallet (domain `api.kviria.com`, URI
`https://api.kviria.com`, a fresh nonce — sign-ins are single-use;
the exact construction is in
[the agent endpoint](/api/agent#building-the-sign-in)) and pass it as
the `SIGN-IN-WITH-X` header:

```bash theme={null}
curl -X POST "https://api.kviria.com/v1/agent?agent=my-agent" \
  -H "Content-Type: application/json" \
  -H "SIGN-IN-WITH-X: $SIWX" \
  -d '{
    "transcript": "I want to drink an espresso around here",
    "anchor": { "lat": 37.76326, "lng": -122.4152 }
  }'
```

* `transcript` - the user's raw message, typos and all. Never paraphrase it.
* `anchor` - the user's current position (`{lat, lng}`).
* `?agent=my-agent` - a namespace label for your agent (not a secret).
* `SIGN-IN-WITH-X` - your wallet's sign-in. The first 50 turns each
  day are free.

A response with several matches looks like this:

```json theme={null}
{
  "decision": "candidates",
  "candidates": [
    { "gers": "...", "name": "Stable Cafe", "location": { "lat": 37.7633, "lng": -122.4150 }, "distanceM": 37 },
    { "gers": "...", "name": "Momi Cafe", "location": { "lat": 37.7628, "lng": -122.4148 }, "distanceM": 52 }
  ]
}
```

Ask the user which one - embedding their identities in a natural question
works best: *"Are you looking for Stable Cafe, or Momi Cafe?"*

## 2. The pick — echo the state back

When the user answers ("the first one"), send their words plus the
**same candidates array** back, verbatim (with a fresh sign-in —
every request carries one):

```bash theme={null}
curl -X POST "https://api.kviria.com/v1/agent?agent=my-agent" \
  -H "Content-Type: application/json" \
  -H "SIGN-IN-WITH-X: $SIWX" \
  -d '{
    "transcript": "the first one",
    "anchor": { "lat": 37.76326, "lng": -122.4152 },
    "candidates": [
      { "gers": "...", "name": "Stable Cafe" },
      { "gers": "...", "name": "Momi Cafe" }
    ]
  }'
```

The pick binds mechanically by position - Kviria never re-guesses.

## 3. The coordinate - through the confirm gate

With a single survivor, Kviria's default is a `confirm` decision: it
hands you the target and waits for the user's yes/no before releasing
the verified coordinate. Ask the user *"Is it Stable Cafe (37 m)?"* and
send their bare answer back (echoing the candidates one more time):

```json theme={null}
{
  "decision": "resolved",
  "target": {
    "gers": "...",
    "name": "Stable Cafe",
    "category": "cafe",
    "location": { "lat": 37.7633, "lng": -122.4150 },
    "distanceM": 37
  },
  "evidence": [
    { "test": "resolve", "result": "pass", "reasonCode": "single_survivor" }
  ],
  "confirmed": true
}
```

That's the whole loop: **narrow, echo, confirm, done.** For zero-touch
agents, pass `"confirmation": "off"` to skip the gate.

## What to try next

* A specific address: `"transcript": "2104 Folsom"` -> a `resolved`
  decision with a house-level coordinate (the door facts ride
  `target.address`; exact addresses verify themselves - no confirm
  gate).
* A relative reference: `"the cafe across from Stable Cafe"` -> Kviria
  resolves the place on the opposite side.
* Your agent can do the mapping itself: read the
  [structured intent](/api/agent) format and skip the transcript entirely.
* Your agent speaks MCP? Connect the [MCP server](/api/mcp) instead of
  calling HTTP directly.

## Limits to know up front

* **5 turns/minute per wallet**; your first **50 turns each day are
  free**. Beyond that, [pay per turn](/api/payments).
* **Beta coverage: San Francisco.** Outside the covered area you get an
  honest `notFound`, not a guess.
* Full limits and error codes: [Rate limits](/api/rate-limits),
  [Errors](/api/errors).
