# Everclaw — API Reference

Complete API reference for the [REDACTED] Lumerin Node proxy-router (consumer mode).

**Base URL:** `http://localhost:8082`
**Auth:** Basic auth using credentials from `~/morpheus/.cookie` (format: `admin:<password>`)
**Swagger:** `http://localhost:8082/swagger/index.html`

---

## Authentication

All endpoints require Basic auth. Read credentials from the `.cookie` file:

```bash
COOKIE_PASS=$(cat ~/morpheus/.cookie | cut -d: -f2)

# Use with curl
curl -s -u "admin:$COOKIE_PASS" http://localhost:8082/...
```

The `.cookie` file is auto-generated by the proxy-router on first start.

---

## Health Check

### GET /healthcheck

Check if the proxy-router is running and healthy.

```bash
curl -s -u "admin:$COOKIE_PASS" http://localhost:8082/healthcheck
```

**Response:** HTTP 200 if healthy.

---

## Blockchain Endpoints

### GET /blockchain/balance

Returns MOR and ETH balance for the configured wallet.

```bash
curl -s -u "admin:$COOKIE_PASS" http://localhost:8082/blockchain/balance | jq .
```

**Response:**
```json
{
  "mor": "88000000000000000000",
  "eth": "50000000000000000"
}
```

Values are in wei (18 decimal places). Divide by 10^18 for human-readable amounts.

---

### POST /blockchain/approve

Approve the Diamond contract to transfer MOR tokens on your behalf.

⚠️ **Uses query parameters, not JSON body.**

```bash
curl -s -u "admin:$COOKIE_PASS" -X POST \
  "http://localhost:8082/blockchain/approve?spender=0x6aBE1d282f72B474E54527D93b979A4f64d3030a&amount=1000000000000000000000"
```

**Query Parameters:**

| Parameter | Type | Description |
|-----------|------|-------------|
| `spender` | address | The Diamond contract address |
| `amount` | uint256 | Amount in wei to approve |

**Response:** Transaction hash.

**Notes:**
- Approve a large amount so you don't need to re-approve frequently
- 1000000000000000000000 = 1000 MOR
- Only needs to be done once unless allowance runs out

---

### GET /blockchain/allowance

Check current MOR allowance for a spender.

```bash
curl -s -u "admin:$COOKIE_PASS" \
  "http://localhost:8082/blockchain/allowance?spender=0x6aBE1d282f72B474E54527D93b979A4f64d3030a"
```

**Query Parameters:**

| Parameter | Type | Description |
|-----------|------|-------------|
| `spender` | address | The contract address to check allowance for |

---

### GET /blockchain/models

List all available models on the [REDACTED] network.

```bash
curl -s -u "admin:$COOKIE_PASS" http://localhost:8082/blockchain/models | jq .
```

**Response:** Array of model objects with IDs, names, and provider info.

---

### GET /blockchain/models/{id}/bids

List bids (provider offers) for a specific model.

```bash
curl -s -u "admin:$COOKIE_PASS" \
  "http://localhost:8082/blockchain/models/0xMODEL_ID/bids" | jq .
```

---

### POST /blockchain/models/{id}/session

Open a new inference session for a model.

⚠️ **Use the model ID, not a bid ID.** Using a bid ID causes `"dial tcp: missing address"`.

```bash
curl -s -u "admin:$COOKIE_PASS" -X POST \
  "http://localhost:8082/blockchain/models/0xMODEL_ID/session" \
  -H "Content-Type: application/json" \
  -d '{"sessionDuration": 3600}'
```

**JSON Body:**

| Field | Type | Description |
|-------|------|-------------|
| `sessionDuration` | integer | Session duration in seconds |

**Response:**
```json
{
  "sessionId": "0xabcdef1234567890...",
  "txHash": "0x...",
  ...
}
```

**Notes:**
- Duration is in seconds: 3600 = 1 hour, 86400 = 1 day
- Two blockchain transactions occur: approve + open
- MOR is staked (locked) for the duration
- Save the `sessionId` — you need it for inference

---

### GET /blockchain/sessions

List all active sessions.

```bash
curl -s -u "admin:$COOKIE_PASS" http://localhost:8082/blockchain/sessions | jq .
```

**Response:** Array of session objects.

---

### POST /blockchain/sessions/{id}/close

Close an active session and reclaim staked MOR.

```bash
curl -s -u "admin:$COOKIE_PASS" -X POST \
  "http://localhost:8082/blockchain/sessions/0xSESSION_ID/close"
```

**Response:** Transaction hash.

**Notes:**
- MOR is returned to your wallet after close
- Gas fee (ETH) is charged for the close transaction
- You can close sessions before they expire

---

## Inference Endpoints

### POST /v1/chat/completions

Send a chat completion request through an active session. **OpenAI-compatible format.**

⚠️ **CRITICAL: `session_id` and `model_id` must be HTTP headers, not JSON body fields.**

```bash
curl -s -u "admin:$COOKIE_PASS" "http://localhost:8082/v1/chat/completions" \
  -H "Content-Type: application/json" \
  -H "session_id: 0xYOUR_SESSION_ID" \
  -H "model_id: 0xYOUR_MODEL_ID" \
  -d '{
    "model": "kimi-k2.5:web",
    "messages": [
      {"role": "system", "content": "You are a helpful assistant."},
      {"role": "user", "content": "Hello!"}
    ],
    "stream": false,
    "temperature": 0.7,
    "max_tokens": 4096
  }'
```

**Required HTTP Headers:**

| Header | Type | Description |
|--------|------|-------------|
| `session_id` | string | Active session ID (hex) |
| `model_id` | string | Blockchain model ID (hex) |
| `Content-Type` | string | `application/json` |

**JSON Body (OpenAI-compatible):**

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `model` | string | Yes | Model name (e.g., "kimi-k2.5:web") |
| `messages` | array | Yes | Chat messages array |
| `stream` | boolean | No | Enable SSE streaming (default: false) |
| `temperature` | float | No | Sampling temperature (0-2) |
| `max_tokens` | integer | No | Maximum tokens to generate |
| `top_p` | float | No | Nucleus sampling parameter |

**Non-streaming Response:**
```json
{
  "id": "chatcmpl-...",
  "object": "chat.completion",
  "created": 1234567890,
  "model": "kimi-k2.5:web",
  "choices": [
    {
      "index": 0,
      "message": {
        "role": "assistant",
        "content": "Hello! How can I help you today?"
      },
      "finish_reason": "stop"
    }
  ],
  "usage": {
    "prompt_tokens": 10,
    "completion_tokens": 8,
    "total_tokens": 18
  }
}
```

**Streaming Response (stream: true):**

Returns Server-Sent Events (SSE):
```
data: {"id":"chatcmpl-...","choices":[{"delta":{"content":"Hello"},"index":0}]}

data: {"id":"chatcmpl-...","choices":[{"delta":{"content":"!"},"index":0}]}

data: [DONE]
```

---

### GET /v1/models

List models the router currently knows about (from models-config.json).

```bash
curl -s -u "admin:$COOKIE_PASS" http://localhost:8082/v1/models | jq .
```

**Response:** OpenAI-compatible model list.

---

## Configuration Endpoints

### GET /config

Get current router configuration.

```bash
curl -s -u "admin:$COOKIE_PASS" http://localhost:8082/config | jq .
```

---

## Key Contract Addresses

| Contract | Address | Chain |
|----------|---------|-------|
| Diamond | `0x6aBE1d282f72B474E54527D93b979A4f64d3030a` | Base (8453) |
| MOR Token | `0x7431aDa8a591C955a994a21710752EF9b882b8e3` | Base (8453) |

---

## Common Patterns

### Full Workflow

```bash
COOKIE_PASS=$(cat ~/morpheus/.cookie | cut -d: -f2)
MODEL_ID="0xb487ee62516981f533d9164a0a3dcca836b06144506ad47a5c024a7a2a33fc58"

# 1. Check balance
curl -s -u "admin:$COOKIE_PASS" http://localhost:8082/blockchain/balance | jq .

# 2. Approve MOR (if not already done)
curl -s -u "admin:$COOKIE_PASS" -X POST \
  "http://localhost:8082/blockchain/approve?spender=0x6aBE1d282f72B474E54527D93b979A4f64d3030a&amount=1000000000000000000000"

# 3. Open session
RESPONSE=$(curl -s -u "admin:$COOKIE_PASS" -X POST \
  "http://localhost:8082/blockchain/models/${MODEL_ID}/session" \
  -H "Content-Type: application/json" \
  -d '{"sessionDuration":3600}')
SESSION_ID=$(echo "$RESPONSE" | jq -r '.sessionId')

# 4. Send inference (headers, not body!)
curl -s -u "admin:$COOKIE_PASS" "http://localhost:8082/v1/chat/completions" \
  -H "Content-Type: application/json" \
  -H "session_id: $SESSION_ID" \
  -H "model_id: $MODEL_ID" \
  -d '{"model":"kimi-k2.5:web","messages":[{"role":"user","content":"Hello"}],"stream":false}' | jq .

# 5. Close session when done
curl -s -u "admin:$COOKIE_PASS" -X POST \
  "http://localhost:8082/blockchain/sessions/${SESSION_ID}/close"
```

### Error Handling

Always check for error responses:

```bash
RESPONSE=$(curl -s -u "admin:$COOKIE_PASS" ...)
ERROR=$(echo "$RESPONSE" | jq -r '.error // empty' 2>/dev/null)
if [[ -n "$ERROR" ]]; then
  echo "Error: $ERROR"
fi
```
