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

# REST API

> HTTP REST API for one-shot prompts

# REST API

The Chucky service provides a REST endpoint for one-shot prompts. This is useful when you don't need a persistent WebSocket session.

<Note>
  For multi-turn conversations or streaming with tools, use the [WebSocket API](/api/websocket) instead.
</Note>

## Endpoint

```
POST https://conjure.chucky.cloud/prompt
```

## Request

### Headers

| Header         | Required | Description                                                                         |
| -------------- | -------- | ----------------------------------------------------------------------------------- |
| `Content-Type` | Yes      | Must be `application/json`                                                          |
| `Accept`       | No       | Response format: `text/event-stream` for SSE, `application/json` for JSON (default) |

### Body

```json theme={null}
{
  "message": "What is the capital of France?",
  "options": {
    "token": "your-jwt-token",
    "model": "claude-sonnet-4-5-20250929",
    "systemPrompt": "You are a helpful assistant.",
    "maxTurns": 5
  }
}
```

### Options

| Field               | Type       | Required | Description                                          |
| ------------------- | ---------- | -------- | ---------------------------------------------------- |
| `token`             | `string`   | Yes      | JWT authentication token                             |
| `model`             | `string`   | No       | Claude model (default: `claude-sonnet-4-5-20250929`) |
| `systemPrompt`      | `string`   | No       | System prompt for Claude                             |
| `tools`             | `array`    | No       | Tool definitions                                     |
| `allowedTools`      | `string[]` | No       | Whitelist of allowed tools                           |
| `disallowedTools`   | `string[]` | No       | Blacklist of blocked tools                           |
| `maxTurns`          | `number`   | No       | Maximum conversation turns                           |
| `maxBudgetUsd`      | `number`   | No       | Max cost for this request                            |
| `maxThinkingTokens` | `number`   | No       | Max tokens for extended thinking                     |
| `outputFormat`      | `object`   | No       | Structured output schema                             |
| `mcpServers`        | `object`   | No       | MCP server configurations                            |

## Response Formats

### JSON Response (Default)

When `Accept: application/json` or no Accept header:

```json theme={null}
{
  "result": {
    "type": "result",
    "subtype": "success",
    "text": "The capital of France is Paris.",
    "total_cost_usd": 0.0012,
    "duration_secs": 1.5,
    "usage": {
      "input_tokens": 50,
      "output_tokens": 20
    }
  },
  "messages": [
    {
      "type": "assistant",
      "subtype": "text",
      "text": "The capital of France is Paris."
    },
    {
      "type": "result",
      "subtype": "success",
      "text": "The capital of France is Paris.",
      "total_cost_usd": 0.0012
    }
  ],
  "sessionId": "550e8400-e29b-41d4-a716-446655440000"
}
```

### SSE Response (Streaming)

When `Accept: text/event-stream`:

```
event: message
data: {"type":"assistant","subtype":"text","text":"The capital of "}

event: message
data: {"type":"assistant","subtype":"text","text":"France is Paris."}

event: message
data: {"type":"result","subtype":"success","text":"The capital of France is Paris.","total_cost_usd":0.0012}

event: done
data: {"sessionId":"550e8400-e29b-41d4-a716-446655440000"}
```

## Error Responses

### Authentication Errors

```json theme={null}
{
  "error": "Token expired"
}
```

Status: `401 Unauthorized`

### Budget Exceeded

```json theme={null}
{
  "error": "user_budget_exhausted",
  "ai": {
    "used": 1000000,
    "remaining": 0,
    "budget": 1000000
  },
  "compute": {
    "used": 3600,
    "remaining": 0,
    "budget": 3600
  }
}
```

Status: `429 Too Many Requests`

### Concurrency Limit

```json theme={null}
{
  "error": "concurrent_limit_reached",
  "active": 5,
  "max": 5,
  "sessions": [
    { "sessionId": "abc123", "userId": "user1", "ageMs": 45000 }
  ]
}
```

Status: `429 Too Many Requests`

### Developer Budget Exceeded

```json theme={null}
{
  "error": "developer_budget_exhausted",
  "used": 500000,
  "available": 0,
  "planSeconds": 500000,
  "poolSeconds": 0
}
```

Status: `402 Payment Required`

## Examples

### cURL - JSON Response

```bash theme={null}
curl -X POST https://conjure.chucky.cloud/prompt \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{
    "message": "What is 2 + 2?",
    "options": {
      "token": "your-jwt-token"
    }
  }'
```

### cURL - SSE Streaming

```bash theme={null}
curl -X POST https://conjure.chucky.cloud/prompt \
  -H "Content-Type: application/json" \
  -H "Accept: text/event-stream" \
  -d '{
    "message": "Write a haiku about coding",
    "options": {
      "token": "your-jwt-token",
      "model": "claude-sonnet-4-5-20250929"
    }
  }'
```

### JavaScript - Fetch with JSON

```javascript theme={null}
const response = await fetch('https://conjure.chucky.cloud/prompt', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Accept': 'application/json',
  },
  body: JSON.stringify({
    message: 'Explain quantum computing briefly',
    options: {
      token: 'your-jwt-token',
      model: 'claude-sonnet-4-5-20250929',
    },
  }),
});

const data = await response.json();
console.log(data.result.text);
```

### JavaScript - SSE Streaming

```javascript theme={null}
const response = await fetch('https://conjure.chucky.cloud/prompt', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Accept': 'text/event-stream',
  },
  body: JSON.stringify({
    message: 'Write a short story',
    options: { token: 'your-jwt-token' },
  }),
});

const reader = response.body.getReader();
const decoder = new TextDecoder();

while (true) {
  const { done, value } = await reader.read();
  if (done) break;

  const chunk = decoder.decode(value);
  const lines = chunk.split('\n');

  for (const line of lines) {
    if (line.startsWith('data: ')) {
      const data = JSON.parse(line.slice(6));
      if (data.type === 'assistant' && data.subtype === 'text') {
        process.stdout.write(data.text);
      }
    }
  }
}
```

### Python - Requests

```python theme={null}
import requests

response = requests.post(
    'https://conjure.chucky.cloud/prompt',
    headers={
        'Content-Type': 'application/json',
        'Accept': 'application/json',
    },
    json={
        'message': 'What is the meaning of life?',
        'options': {
            'token': 'your-jwt-token',
        },
    },
)

data = response.json()
print(data['result']['text'])
```

***

# Usage API

Check current token usage against budget limits.

## Endpoint

```
GET https://conjure.chucky.cloud/usage
```

## Request

### Headers

| Header          | Required | Description                           |
| --------------- | -------- | ------------------------------------- |
| `Authorization` | Yes      | Bearer token: `Bearer your-jwt-token` |

## Response

```json theme={null}
{
  "user_id": "demo-user",
  "issuer_id": "jd77az049xjwsv0pbjqbrkfjws7z5136",
  "window": "day",
  "window_start": "2026-01-14T00:00:00.000Z",
  "allowed": true,
  "ai": {
    "used": 150000,
    "remaining": 4850000,
    "budget": 5000000
  },
  "compute": {
    "used": 84,
    "remaining": 359916,
    "budget": 360000
  }
}
```

### Response Fields

| Field               | Type      | Description                                                  |
| ------------------- | --------- | ------------------------------------------------------------ |
| `user_id`           | `string`  | User ID from token (`sub` claim)                             |
| `issuer_id`         | `string`  | Project ID from token (`iss` claim)                          |
| `window`            | `string`  | Budget window: `hour`, `day`, `week`, `month`, or `lifetime` |
| `window_start`      | `string`  | ISO timestamp when current window started                    |
| `allowed`           | `boolean` | Whether the user can continue (within budget)                |
| `ai.used`           | `number`  | AI cost used in microdollars                                 |
| `ai.remaining`      | `number`  | AI cost remaining in microdollars                            |
| `ai.budget`         | `number`  | Total AI budget in microdollars                              |
| `compute.used`      | `number`  | Compute time used in seconds                                 |
| `compute.remaining` | `number`  | Compute time remaining in seconds                            |
| `compute.budget`    | `number`  | Total compute budget in seconds                              |

<Note>
  AI cost is tracked in **microdollars** (1 USD = 1,000,000 microdollars).
  Compute time is tracked in **seconds**.
</Note>

## Examples

### cURL

```bash theme={null}
curl -H "Authorization: Bearer your-jwt-token" \
  https://conjure.chucky.cloud/usage
```

### JavaScript

```javascript theme={null}
const response = await fetch('https://conjure.chucky.cloud/usage', {
  headers: {
    'Authorization': `Bearer ${token}`
  }
});

const usage = await response.json();

// Check remaining budget
console.log(`AI remaining: $${usage.ai.remaining / 1_000_000}`);
console.log(`Compute remaining: ${usage.compute.remaining}s`);

if (!usage.allowed) {
  console.log('Budget exhausted!');
}
```

### Python

```python theme={null}
import requests

response = requests.get(
    'https://conjure.chucky.cloud/usage',
    headers={'Authorization': f'Bearer {token}'}
)

usage = response.json()
print(f"AI remaining: ${usage['ai']['remaining'] / 1_000_000:.2f}")
print(f"Compute remaining: {usage['compute']['remaining']}s")
```

***

## Comparison: REST vs WebSocket

| Feature                  | REST `/prompt`          | WebSocket `/ws`  |
| ------------------------ | ----------------------- | ---------------- |
| Multi-turn conversations | No                      | Yes              |
| Session persistence      | No                      | Yes              |
| Streaming                | SSE only                | Full duplex      |
| Client-side tools        | Limited                 | Full support     |
| Best for                 | Simple one-shot queries | Interactive apps |
