# Quickstart

> Five minutes from no token to discovered market to placed order to confirmed fill. Python, copy-paste runnable, browser-free after the one-time token setup.

<Callout type="info" title="API order placement">
For API trading, use [pre-signed orders](/docs/api-traders/pre-signed-orders).
Server-side signing may slow order ingestion. Follow the
[one-time setup](/docs/api-traders/pre-signed-orders#one-time-setup) and grant
`orders:place_signed` for signed single-order and batch submissions.
</Callout>

The examples below demonstrate server-signed placement with `orders:place`.
For an API trading integration, follow the pre-signed guide above; it uses
`orders:place_signed` and a locally signed order envelope.

## 0. One-time browser setup [#0-one-time-browser-setup]

If you haven't signed in yet:

1. Open the web app, sign in.
2. Wait for your account setup to finish. The app shows when your on-chain
   account and trading approvals are ready.
3. Open **Settings → API Tokens**, click **Create token**, and pick the
   scopes used by this server-signed example:
   ```
   portfolio:read, orders:read, orders:place,
   orders:cancel, orders:cancel_all
   ```
   (Reading the orderbook and discovering markets don't need a
   scope — those endpoints are public.)
4. **Copy the token immediately.** It's shown exactly once.

After this you never need the browser again for trading.

## 1. Setup [#1-setup]

```bash
pip install requests
```

```bash
export AGARA_BASE_URL="https://app.agara.xyz"
export AGARA_WS_URL="wss://app.agara.xyz"
export AGARA_CHAIN_ID="8453"
export AGARA_COLLATERAL_ADDRESS="0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913"
export AGARA_CONDITIONAL_TOKENS_ADDRESS="0xe12D566cE5Dd8d817488E85a81386878649e3A18"
export AGARA_CTF_EXCHANGE_ADDRESS="0xD06f3fA925D35077A11dB42c6614D684f10B2aD6"
```

```bash
export AGARA_TOKEN="agt_..."
```

```python
import os, time, requests

AGARA_BASE_URL = os.environ["AGARA_BASE_URL"]
TOKEN = os.environ["AGARA_TOKEN"]
HEADERS = {"Authorization": f"Bearer {TOKEN}"}

def call(method, path, json=None, auth=True):
    headers = HEADERS if auth else {}
    r = requests.request(method, f"{AGARA_BASE_URL}{path}", headers=headers, json=json)
    r.raise_for_status()
    return r.json() if r.content else None
```

## 2. Discover an event [#2-discover-an-event]

Find something to trade. Browse, filter by category, exclude
finished events — the markets API is public, no auth needed. See
[Markets](/docs/markets) for the full list of filters.

```python
listing = call("GET", "/api/v1/events?limit=20&exclude_ended=true&source=AGARA", auth=False)
for ev in listing["events"]:
    print(ev["slug"], "—", ev["title"])
```

Once you've picked an event, fetch the full detail by its slug. The
response carries the event's markets and every outcome on each
market — including the `token_id` you'll trade against. Recurring
series return the live window plus their most recent cycles, not
the full history.

```python
EVENT_SLUG = next(ev["slug"] for ev in listing["events"] if ev["is_accepting_orders"])

ev = call("GET", f"/api/v1/events/{EVENT_SLUG}", auth=False)

market  = next(m for m in ev["markets"] if m["is_accepting_orders"])
outcome = market["outcomes"][0]

TOKEN_ID = outcome["token_id"]
print(f"trading {market['display_label']} — {outcome['label']} → {TOKEN_ID[:12]}…")
```

## 3. Read the orderbook [#3-read-the-orderbook]

```python
book = call("GET", f"/trade/v1/orderbook/{TOKEN_ID}", auth=False)
# Either side can be empty on a brand-new market or one that just
# saw a sweep — guard before indexing.
best_bid = book["bids"][0]["price"] if book["bids"] else None
best_ask = book["asks"][0]["price"] if book["asks"] else None
print(f"best bid {best_bid} / ask {best_ask}")
```

Sample output:

```
best bid 0.27 / ask 0.29
```

## 4. Place a limit order [#4-place-a-limit-order]

Buy 1 share at 0.30 collateral units. Amounts go on the wire in **micro units
encoded as strings** — multiply by 1,000,000, stringify. (See
[Conventions](/docs/conventions#amounts-are-in-micro-units) for why.)

```python
resp = call("POST", "/trade/v1/orders", json={
    "token_id": TOKEN_ID,
    "side": "BUY",
    "type": "LIMIT",
    "time_in_force": "GTC",
    "price_micro": str(int(0.30 * 1_000_000)),
    "shares_micro": str(1 * 1_000_000),
})

order_id = resp["order_id"]
print(f"placed order {order_id}, status {resp['status']}")
```

Sample output:

```
placed order 9c4a3e7d-12b4-4f8e-9a3c-d2c7f0a45e1b, status PENDING
```

`PENDING` is the initial acknowledgement — we've accepted the order and
are routing it to the exchange, not that it's filled. It may progress through
`SUBMITTING` and `OPEN`, fill immediately, or be rejected asynchronously.

## 5. Watch the order [#5-watch-the-order]

Poll until it reaches a terminal status, or until you give up and
cancel. Response amounts come back as strings — wrap in `int(...)`
when you need to do math on them.

```python
DEADLINE = time.time() + 30

while time.time() < DEADLINE:
    order = call("GET", f"/trade/v1/orders/{order_id}")["order"]
    filled = int(order["size_matched_micro"])
    total = int(order["original_size_micro"])
    print(f"status={order['status']} filled={filled}/{total}")
    if order["is_terminal"]:
        break
    time.sleep(1.0)
else:
    print("not filled in 30s — cancelling")
    call("DELETE", f"/trade/v1/orders/{order_id}")
```

If it fills:

```
status=PENDING filled=0/1000000
status=OPEN filled=0/1000000
status=PARTIALLY_FILLED filled=500000/1000000
status=MATCHED filled=1000000/1000000
```

## 6. See your fills [#6-see-your-fills]

```python
trades = call("GET", "/trade/v1/portfolio/trades")
recent = sorted(trades["trades"], key=lambda t: t["executed_at"], reverse=True)[:5]

for t in recent:
    shares = int(t["shares_micro"]) / 1e6
    price  = int(t["price_micro"]) / 1e6
    fee    = int(t["fee_micro"]) / 1e6
    print(f"{t['executed_at']}  {t['side']}  {shares:.2f}sh "
          f"@ {price:.4f} collateral  fee={fee:.6f} collateral")
```

## 7. Cleanup (optional) [#7-cleanup-optional]

If you have leftover open orders from testing:

```python
call("POST", "/trade/v1/orders/cancel-all")
```

## Next [#next]

<Cards>
<Card title="Markets" href="/docs/markets">
Discovery API in full: filters, pagination, `condition_id` vs `token_id`.
</Card>

<Card title="Orders" href="/docs/orders">
Every order operation, time-in-force options, post-only behavior, common patterns.
</Card>

<Card title="Orderbook" href="/docs/orderbook">
Depth details, polling cadence, price grid.
</Card>

<Card title="Conventions" href="/docs/conventions">
Micro units, identifiers, pagination, status lifecycle.
</Card>

<Card title="Errors and recovery" href="/docs/errors">
Typed failure codes, request IDs, safe retries, and asynchronous failures.
</Card>

<Card title="Authentication" href="/docs/authentication">
Scope reference, rotation, revocation.
</Card>

<Card title="API reference" href="/docs/api-reference">
Every endpoint, parameter, response shape, and status code.
</Card>
</Cards>

## Full script [#full-script]

This script uses the same server-signed placement shown above.

```python
import os, time, requests

AGARA_BASE_URL = os.environ["AGARA_BASE_URL"]
TOKEN = os.environ["AGARA_TOKEN"]
HEADERS = {"Authorization": f"Bearer {TOKEN}"}

def call(method, path, json=None, auth=True):
    headers = HEADERS if auth else {}
    r = requests.request(method, f"{AGARA_BASE_URL}{path}", headers=headers, json=json)
    r.raise_for_status()
    return r.json() if r.content else None

listing = call(
    "GET",
    "/api/v1/events?limit=20&exclude_ended=true&source=AGARA",
    auth=False,
)
event_slug = next(ev["slug"] for ev in listing["events"] if ev["is_accepting_orders"])
ev = call("GET", f"/api/v1/events/{event_slug}", auth=False)
market = next(m for m in ev["markets"] if m["is_accepting_orders"])
outcome = market["outcomes"][0]
TOKEN_ID = outcome["token_id"]
print(f"trading {market['display_label']} — {outcome['label']}")

book = call("GET", f"/trade/v1/orderbook/{TOKEN_ID}", auth=False)
best_bid = book["bids"][0]["price"] if book["bids"] else None
best_ask = book["asks"][0]["price"] if book["asks"] else None
print(f"best bid {best_bid} / ask {best_ask}")

resp = call("POST", "/trade/v1/orders", json={
    "token_id": TOKEN_ID,
    "side": "BUY",
    "type": "LIMIT",
    "time_in_force": "GTC",
    "price_micro": str(int(0.30 * 1_000_000)),
    "shares_micro": str(1 * 1_000_000),
})
order_id = resp["order_id"]
print(f"placed {order_id}")

deadline = time.time() + 30
while time.time() < deadline:
    order = call("GET", f"/trade/v1/orders/{order_id}")["order"]
    filled = int(order["size_matched_micro"]) / 1e6
    print(f"  {order['status']} filled={filled}")
    if order["is_terminal"]:
        break
    time.sleep(1.0)
else:
    print("cancelling")
    call("DELETE", f"/trade/v1/orders/{order_id}")
```
