# REST API Reference

The Olakai REST API enables you to build custom clients for submitting AI activity reports directly to the platform. Use this API when you need fine-grained control over data submission, custom integrations, or when SDK clients don't meet your specific requirements.

**Note:** The REST API is for traffic reporting (sending prompts, responses, and metrics). For configuration management, use the [Olakai CLI](/docs/olakai/olakai-cli).

The REST API provides the same functionality as our SDK clients but gives you complete control over HTTP requests, error handling, and data formatting. It's ideal for enterprise integrations, custom monitoring tools, and applications requiring specific networking configurations.

> **For AI Assistants**: If you're building an AI assistant or agent that needs to integrate with Olakai, see the [llms.txt](/llms.txt) file for a concise guide on using the Olakai API, including deployment scenarios and code examples.

## Quick Start

Here's a complete example of submitting an AI activity report:

```bash
curl -X POST "https://app.olakai.ai/api/monitoring/prompt" \
  -H "Content-Type: application/json" \
  -H "x-api-key: your-api-key-here" \
  -d '{
    "prompt": "Write a product description for wireless headphones",
    "response": "Experience crystal-clear sound with our premium wireless headphones...",
    "app": "my-ai-app",
    "task": "Content Generation",
    "tokens": 150
  }'
```

> **Note**: Session grouping is handled automatically. Related requests within the same API key session are grouped together.

## Authentication

The API supports two authentication methods:

### API Key Authentication (Recommended)

Include your API key in the `x-api-key` header:

```http
x-api-key: your-api-key-here
```

### Passive Authentication (Alternative)

For applications where API keys aren't feasible, use account headers (note that this requires the account setting extensionApiKeyRequired to be false):

```http
x-account-id: your-account-id
x-email: user@example.com
```

```http
x-account-id: your-account-id
x-device-id: device123
```

**Obtaining API Keys**: Generate API keys in your Olakai dashboard under Settings → API Keys.

## API Reference

### Base URL

```
https://app.olakai.ai/api/monitoring
```

### Endpoints

| Method | Endpoint     | Description                         |
| ------ | ------------ | ----------------------------------- |
| `POST` | `/prompt`    | Submit AI activity reports          |
| `GET`  | `/prompt/me` | Validate authentication credentials |

### Request Parameters

| Parameter     | Type   | Required | Description                                                                                                                                                                                                                       |
| ------------- | ------ | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `prompt`      | string | Yes      | The AI prompt/input sent to the model                                                                                                                                                                                             |
| `response`    | string | Yes      | The AI response/output received from the model                                                                                                                                                                                    |
| `app`         | string | Yes      | Your application identifier                                                                                                                                                                                                       |
| `task`        | string | No       | Task category name. **Must be one of the supported task categories** - see [Task Categories and Subtasks](/docs/olakai/task-categories-and-subtasks) for the complete list.                                                       |
| `subTask`     | string | No       | Specific sub-task name. **Must be one of the supported subtasks** for the selected task category - see [Task Categories and Subtasks](/docs/olakai/task-categories-and-subtasks) for the complete list.                           |
| `tokens`      | number | No       | Token count used by the AI model                                                                                                                                                                                                  |
| `requestTime` | number | No       | Request duration in milliseconds                                                                                                                                                                                                  |
| `providerCostUsd` | number | No   | The charge the provider reported for this call, in USD, from 0 to 10,000 (OpenRouter returns it as `usage.cost`). When present, Olakai uses it for cost instead of a token-based estimate. Honoured only on SDK traffic, not on Zapier or browser extension events. An invalid value is dropped; the event is still accepted. |
| `customData`  | object | No       | Custom values                                                                                                                                                                                                                     |
| `chatId`      | string | No       | Groups the turns of one conversation into a session. Send the same value on every turn. Required for CHAT-scoped KPIs such as Time Saved, which score the whole conversation. The SDKs' `sessionId` option is sent as this field. |
| `cliVersion`  | string | No       | Version of the reporting client (e.g. the olakai-cli or SDK version). Optional; max 32 characters.                                                                                                                                |

> **Complete Parameter Reference**: See [API Parameters Reference](data-architecture.md) for detailed parameter descriptions and examples.

> **Sessions are opt-in over REST.** The API groups events into a session only when the body carries `chatId`. There is no `sessionId` body field: the TypeScript and Python SDKs accept `sessionId` and send it as `chatId`. An event without `chatId` is stored on its own, so CHAT-scoped KPIs never run for it and `olakai activity sessions` does not list it.

### Response Format

**Success Response:**

```json
{
  "success": true,
  "totalRequests": 1,
  "successCount": 1,
  "failureCount": 0,
  "message": "All prompt requests logged successfully"
}
```

**Invalid events.** When you send events with an agent API key, each event's fields are checked when it arrives. An event that fails the check (for example one missing `prompt` or `response`, or with a `tokens` value that is not a number) is not stored. The response still has status `200`, but it reports the failure. Valid events in the same request are stored as usual:

```json
{
  "success": false,
  "totalRequests": 2,
  "successCount": 1,
  "failureCount": 1,
  "results": [
    { "index": 1, "success": false, "error": "response: Invalid input" }
  ],
  "message": "1 of 2 prompt request(s) were not logged because they are invalid: response: Invalid input"
}
```

`index` is the event's position in the request array (0 for a single object). Check `success` rather than the status code alone. A few problems can only be found after the event is accepted, for example a `customData` value that does not match its declared Custom Data type. Those events show an **Error** badge in **Global Settings → Audit & Logs → Live Feed**.

**Error Response:**

```json
{
  "error": "Authentication required"
}
```

## Implementation Examples

### cURL

```bash
#!/bin/bash

API_KEY="your-api-key-here"
ENDPOINT="https://app.olakai.ai/api/monitoring/prompt"

# Submit single activity
curl -X POST "$ENDPOINT" \
  -H "Content-Type: application/json" \
  -H "x-api-key: $API_KEY" \
  -d '{
    "prompt": "Generate a blog post about AI trends",
    "response": "Here is your blog post about AI trends...",
    "app": "content-generator",
    "task": "Content Development",
    "subTask": "blog writing",
    "tokens": 200
  }'
```

### Python

```python
import requests
import json
from typing import Dict, Any

class OlakaiClient:
    def __init__(self, api_key: str, base_url: str = "https://app.olakai.ai"):
        self.api_key = api_key
        self.base_url = base_url
        self.session = requests.Session()
        self.session.headers.update({
            "Content-Type": "application/json",
            "x-api-key": api_key
        })

    def submit_activity(self, activity_data: Dict[str, Any]) -> Dict[str, Any]:
        """Submit AI activity to Olakai"""
        try:
            response = self.session.post(
                f"{self.base_url}/api/monitoring/prompt",
                json=activity_data
            )
            response.raise_for_status()
            return response.json()
        except requests.exceptions.RequestException as e:
            return {"error": str(e)}

# Usage example
client = OlakaiClient("your-api-key-here")

activity = {
    "prompt": "Analyze customer feedback sentiment",
    "response": "The feedback shows positive sentiment...",
    "app": "sentiment-analyzer",
    "task": "Data Processing & Analysis",
    "subTask": "sentiment analysis",
    "tokens": 150,
    "customData": {
        "Department": "customer-support",
        "Project": "sentiment-analysis"
    }
}

result = client.submit_activity(activity)
print(result)
```

### JavaScript/Node.js

```javascript
class OlakaiClient {
  constructor(apiKey, baseUrl = "https://app.olakai.ai") {
    this.apiKey = apiKey;
    this.baseUrl = baseUrl;
  }

  async submitActivity(activityData) {
    try {
      const response = await fetch(`${this.baseUrl}/api/monitoring/prompt`, {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
          "x-api-key": this.apiKey,
        },
        body: JSON.stringify(activityData),
      });

      if (!response.ok) {
        throw new Error(`HTTP error! status: ${response.status}`);
      }

      return await response.json();
    } catch (error) {
      return { error: error.message };
    }
  }
}

// Usage example
const client = new OlakaiClient("your-api-key-here");

const activity = {
  prompt: "Generate product recommendations",
  response: "Based on your preferences, I recommend...",
  app: "recommendation-engine",
  task: "Customer Experience",
  subTask: "product recommendations",
  tokens: 120,
  customMetrics: {
    Satisfaction: 4.5, // user satisfaction score
    Accuracy: 0.95, // recommendation accuracy
  },
};

client
  .submitActivity(activity)
  .then((result) => console.log(result))
  .catch((error) => console.error(error));
```

### Go

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "net/http"
)

type OlakaiClient struct {
    APIKey  string
    BaseURL string
    Client  *http.Client
}

type ActivityData struct {
    Prompt           string                 `json:"prompt"`
    Response         string                 `json:"response"`
    App              string                 `json:"app"`
    Task             string                 `json:"task,omitempty"`
    SubTask          string                 `json:"subTask,omitempty"`
    Tokens           int                    `json:"tokens,omitempty"`
    RequestTime      int                    `json:"requestTime,omitempty"`
    CustomData       map[string]any         `json:"customData,omitempty"`
    ChatID           string                 `json:"chatId,omitempty"`
}

type APIResponse struct {
    Success       bool   `json:"success"`
    TotalRequests int    `json:"totalRequests"`
    SuccessCount  int    `json:"successCount"`
    FailureCount  int    `json:"failureCount"`
    Message       string `json:"message"`
    Error         string `json:"error,omitempty"`
}

func NewOlakaiClient(apiKey string) *OlakaiClient {
    return &OlakaiClient{
        APIKey:  apiKey,
        BaseURL: "https://app.olakai.ai",
        Client:  &http.Client{},
    }
}

func (c *OlakaiClient) SubmitActivity(activity ActivityData) (*APIResponse, error) {
    jsonData, err := json.Marshal(activity)
    if err != nil {
        return nil, err
    }

    req, err := http.NewRequest("POST", c.BaseURL+"/api/monitoring/prompt", bytes.NewBuffer(jsonData))
    if err != nil {
        return nil, err
    }

    req.Header.Set("Content-Type", "application/json")
    req.Header.Set("x-api-key", c.APIKey)

    resp, err := c.Client.Do(req)
    if err != nil {
        return nil, err
    }
    defer resp.Body.Close()

    body, err := io.ReadAll(resp.Body)
    if err != nil {
        return nil, err
    }

    var apiResp APIResponse
    err = json.Unmarshal(body, &apiResp)
    if err != nil {
        return nil, err
    }

    return &apiResp, nil
}

// Usage example
func main() {
    client := NewOlakaiClient("your-api-key-here")

    activity := ActivityData{
        Prompt:   "Translate this text to Spanish",
        Response: "Aquí está la traducción al español...",
        App:      "translation-service",
        Task:     "Language Services",
        SubTask:  "translation",
        Tokens:   80,
    }

    result, err := client.SubmitActivity(activity)
    if err != nil {
        fmt.Printf("Error: %v\n", err)
        return
    }

    fmt.Printf("Result: %+v\n", result)
}
```

## Error Handling

| Status Code | Error                 | Description                                       | Solution                             |
| ----------- | --------------------- | ------------------------------------------------- | ------------------------------------ |
| `200`       | Success               | Request processed. Check `success`: invalid events are reported in `results` | Fix the fields named in `results[].error` |
| `400`       | Bad Request           | The body is not valid JSON, or the request could not be processed (see `details`) | Check the request body |
| `401`       | Unauthorized          | Invalid or missing API key                        | Verify API key in `x-api-key` header |
| `500`       | Internal Server Error | Server-side processing error                      | Retry request or contact support     |

## Best Practices

- **Choose the Right Deployment Strategy**: Olakai tracks AI interactions to measure business value, productivity improvements, efficiency gains, and ROI. For **agentic workflows** that combine multiple LLM calls, track the entire workflow as one unit with a single API call. For **individual LLM calls** where each represents a distinct task, track each call separately. See the [Deployment Scenarios section](/docs/olakai/data-architecture#deployment-scenarios-when-to-track-at-workflow-vs-prompt-level) for detailed guidance.
- **Batch Requests**: Send multiple activities in a single request using arrays to improve performance
- **Error Handling**: Always implement retry logic with exponential backoff for failed requests
- **Rate Limiting**: Respect API rate limits and implement appropriate delays between requests
- **Data Validation**: Validate required fields (`prompt`, `response`, `app`) before sending requests
- **Monitoring**: Use the `/prompt/me` endpoint to validate authentication before submitting data
