KOVA API Reference

The KOVA API lets you manage strategies, submit portfolios, and generate briefs programmatically. Same evaluation engine as the web app, accessible over REST.

Base URL: https://kovatools.com/api/v1


Authentication

All API requests require a Bearer token in the Authorization header.

Authorization: Bearer kova_tk_xxxxxxxxxxxxxxxxxxxx

Getting a token: Log in to KOVA, go to Settings, and generate an API token. The token is shown once at creation — copy it immediately. Tokens can be revoked from the same page.


Response Format

Every response wraps the resource in a named key plus a meta object:

{
  "strategy": { ... },
  "meta": {
    "request_id": "abc-123",
    "timestamp": "2026-02-15T12:00:00Z"
  }
}

Collections use the plural key ("strategies", "briefs"). Errors use "error":

{
  "error": {
    "code": "not_found",
    "message": "Strategy not found"
  },
  "meta": { ... }
}

Endpoints

List Strategies

GET /api/v1/strategies

Returns all strategies owned by the authenticated user.

Response (200):

{
  "strategies": [
    {
      "uuid": "a1b2c3d4-...",
      "name": "Long-Term Growth",
      "content_summary": "My strategy focuses on...",
      "created_at": "2026-01-01T00:00:00Z",
      "updated_at": "2026-02-01T00:00:00Z"
    }
  ],
  "meta": { ... }
}

Get Strategy

GET /api/v1/strategies/:uuid

Returns full details of a strategy, including the complete text.

Response (200):

{
  "strategy": {
    "uuid": "a1b2c3d4-...",
    "name": "Long-Term Growth",
    "content": "Full strategy text...",
    "created_at": "2026-01-01T00:00:00Z",
    "updated_at": "2026-02-01T00:00:00Z"
  },
  "meta": { ... }
}

Create Strategy

POST /api/v1/strategies

Creates a new strategy for the authenticated user.

Request body:

{
  "content": "Buy and hold growth stocks. Max 20% per position. Rebalance quarterly.",
  "name": "Long-Term Growth"
}
Field Type Required Description
content string Yes Full strategy text (supports Markdown)
name string No Display name for the strategy

Response (201 Created):

{
  "strategy": {
    "uuid": "a1b2c3d4-...",
    "name": "Long-Term Growth",
    "content": "Buy and hold growth stocks. Max 20% per position. Rebalance quarterly.",
    "created_at": "2026-02-15T12:00:00Z",
    "updated_at": "2026-02-15T12:00:00Z"
  },
  "meta": { ... }
}

Update Strategy

PUT /api/v1/strategies/:uuid

Updates an existing strategy. Only provided fields are changed.

Request body:

{
  "content": "Updated strategy text...",
  "name": "Renamed Strategy"
}

Response (200): Same shape as Get Strategy.


Delete Strategy

DELETE /api/v1/strategies/:uuid

Permanently deletes a strategy.

Response: 204 No Content


Create Brief

POST /api/v1/strategies/:uuid/briefs

Submit a portfolio and trigger asynchronous brief generation. Returns immediately with a brief ID — poll the show endpoint for results.

Request body:

{
  "portfolio": {
    "source": "text",
    "content": "AAPL 100 shares at $150, MSFT 50 shares at $380, $12,000 cash"
  },
  "context": "Risk tolerance: aggressive. Current bias: { AAPL: bearish, MSFT: neutral }. RSI(14): AAPL 72, MSFT 45. VIX: 18.5"
}

Portfolio source types:

Source Content content_type
text Plain text description Not needed
file Base64-encoded file Required (application/pdf, text/csv, image/png)
json Structured JSON (portfolio_v1 schema) Not needed

context (optional): Any string (ideally markdown) that helps Kova produce a more accurate evaluation. Use it to provide risk tolerance, market outlook, technical indicators, or any signal relevant to your strategy. Ephemeral — applies to this brief only.

Response (202 Accepted):

{
  "brief": {
    "id": "brief-uuid",
    "status": "processing",
    "poll_url": "/api/v1/strategies/strategy-uuid/briefs/brief-uuid"
  },
  "meta": { ... }
}

Get Brief (Poll for Status)

GET /api/v1/strategies/:uuid/briefs/:id

Returns the current state of a brief. Poll this endpoint after creating a brief until status is completed or error.

Status: processing

{
  "brief": {
    "id": "brief-uuid",
    "status": "processing"
  },
  "meta": { ... }
}

Status: completed

{
  "brief": {
    "id": "brief-uuid",
    "status": "completed",
    "alignment": {
      "score": 0.82,
      "label": "Aligned"
    },
    "content": "## Full markdown brief...",
    "summary": "Portfolio is broadly aligned with growth strategy.",
    "target_allocations": [...],
    "compliance_checks": [...],
    "context_at_generation": "FOMC raised rates 25bps today.",
    "generated_at": "2026-02-15T12:00:00Z"
  },
  "meta": { ... }
}

Status: error

{
  "brief": {
    "id": "brief-uuid",
    "status": "error",
    "error": {
      "code": "processing_failed",
      "message": "Could not process portfolio data."
    }
  },
  "meta": { ... }
}

List Briefs

GET /api/v1/strategies/:uuid/briefs

Returns all completed briefs for a strategy, most recent first.

Response (200):

{
  "briefs": [
    {
      "id": "brief-uuid",
      "alignment": {
        "score": 0.82,
        "label": "Aligned"
      },
      "summary": "Portfolio is broadly aligned...",
      "generated_at": "2026-02-15T12:00:00Z"
    }
  ],
  "meta": { ... }
}

Brief Lifecycle

Creating a brief is asynchronous. The flow:

  1. POST to create — returns 202 Accepted with status: processing
  2. Poll the GET endpoint until status changes
  3. Terminal states: completed (brief is ready) or error (something failed)
processing → completed
processing → error

Recommended polling interval: start at 2 seconds, back off to 5 seconds.


Portfolio JSON Schema

When using "source": "json" in the create brief endpoint, the content must match the portfolio_v1 schema.

Required fields: schema_version, stocks, options, cash, timestamp, notes

{
  "schema_version": "1.0.0",
  "stocks": [
    {
      "ticker": "AAPL",
      "shares": 100,
      "cost_basis": 150.00
    },
    {
      "ticker": "MSFT",
      "shares": 50,
      "cost_basis": 380.00
    }
  ],
  "options": [
    {
      "ticker": "AAPL",
      "type": "call",
      "strike": 200,
      "expiry": "2026-06-20",
      "contracts": 2,
      "side": "short",
      "premium": 5.50
    }
  ],
  "cash": 12000.00,
  "timestamp": "2026-02-15T12:00:00Z",
  "notes": ["Cost basis estimated for MSFT"]
}

Stocks

Field Type Required Description
ticker string Yes Ticker symbol (1-8 chars, letters/numbers/dots)
shares number Yes Number of shares (>= 0)
cost_basis number No Average cost per share

Options

Field Type Required Description
ticker string Yes Underlying ticker symbol
type string Yes "call" or "put"
strike number No Strike price
expiry string No Expiration date (YYYY-MM-DD)
contracts integer No Number of contracts (>= 1)
side string No "long" or "short"
premium number No Premium paid/received per share

Other Fields

Field Type Description
cash number Cash balance in dollars (negative for margin)
timestamp string ISO 8601 UTC timestamp (YYYY-MM-DDTHH:MM:SSZ)
notes array of strings Notes about ambiguities or missing data

Alignment Scale

Score Label
0.85 – 1.00 Strongly Aligned
0.70 – 0.84 Aligned
0.55 – 0.69 Partially Aligned
0.40 – 0.54 Drifting
0.00 – 0.39 Off-Track

Error Codes

HTTP Status Code Meaning
401 unauthorized Missing or invalid API token
404 not_found Resource doesn't exist or doesn't belong to you
422 invalid_params Invalid request parameters (for example, malformed portfolio payload or unsupported live_inputs)
422 validation_failed Model validation failed (for example, missing strategy content on create/update)