Issue model (stories & bugs)

Flik stores stories and bugs as a single kind of record: an issue. The type field is either story or bug. Everything below is the canonical JSON shape returned by the API and accepted on create/update (snake_case keys). The CLI and MCP are thin clients over this model—they do not define a separate schema.

Authentication: All issue endpoints use the CLI API: Authorization: Bearer <api_key>, and org context via X-Flik-Org when your key is org-scoped. Paths below are under /api/cli.


API routes (summary)

Method Path Purpose
GET /projects/:acronym/stories List stories in the project
POST /projects/:acronym/stories Create a story (type is story)
GET /projects/:acronym/bugs List bugs
POST /projects/:acronym/bugs Create a bug (type is bug)
GET /projects/:acronym/stories/:id or .../bugs/:id Get one issue by id
PATCH /projects/:acronym/stories/:id or .../bugs/:id Update one issue (partial)
DELETE /projects/:acronym/stories/:id or .../bugs/:id Delete one issue
GET /projects/:acronym/objects/:id Get story or bug by id (same payload)
PATCH /projects/:acronym/objects/:id Update story or bug by id
DELETE /projects/:acronym/objects/:id Delete story or bug by id

Query parameters on list: optional assigned_to (Clerk user id, or the API may resolve me where supported).

List responses: { "ok", "code", "count", "items": [ ... ] }. Single-issue responses: { "ok", "code", "item": { ... } }. Create responses: { "ok", "code", ... } with the same fields as one issue object at the top level (plus ok / code).


Identity & scope

JSON key Type Description
id string Stable display id: <project_acronym>-<sequence> (e.g. mypr-1). Assigned by the server on create.
type string story or bug. Fixed by whether you POST to /stories or /bugs.
project_id string Internal project id (not the acronym). Read-only for clients.

Field reference

Applies to: both = meaningful for every issue; story / bug = primarily used for that type (other type may store empty or zero values).

Create: fields omitted from the JSON body use the defaults below (where noted). PATCH: only include keys you want to change; omitted keys are left unchanged.

Arrays on PATCH: labels, blocks, and blocked_by are replaced in full when you send them—send the complete new list.

JSON key Type Applies to Required on create Default on create (if omitted) PATCH Description
title string both Yes Yes Short summary of the work item.
assigned_to string both No (empty) Yes Clerk user id of the assignee. Empty means unassigned.
status string both No open Yes Workflow: open, in_progress, done, cancelled (lowercase). Invalid values are rejected.
priority string both No medium Yes Free-form label; default applied by the server is medium.
points integer story No 0 Yes Story points. Typically 0 for bugs unless you use points on bugs too.
notes string story† No (empty) Yes Short notes.
severity string bug No medium Yes Bug severity (e.g. low/medium/high); server default medium.
description string both No (empty) Yes Longer body text. Recommended for detailed specs (stories) and bug narratives.
acceptance_criteria string story No (empty) Yes Story acceptance criteria (often markdown-style text).
steps_to_reproduce string bug No (empty) Yes Bug reproduction steps.
expected string bug No (empty) Yes Expected behavior.
actual string bug No (empty) Yes Actual behavior observed.
environment string bug No (empty) Yes Where it happens (e.g. prod, staging, browser).
regression boolean bug No false Yes Whether this is a regression.
affected_version string bug No (empty) Yes Version affected.
fixed_in_version string bug No (empty) Yes Version containing the fix (when known).
due_at string both No (empty) Yes Due date/time; use RFC3339 (e.g. 2026-03-20T17:00:00Z).
labels array of string both No (none) Yes Tags; empty strings are stripped on write.
component string both No (empty) Yes Component, area, or subsystem name.
external_ref string both No (empty) Yes Link to an external system (e.g. GitHub issue URL).
metadata object both No (none) Yes Arbitrary JSON-serializable key/value map for integrations. Replaced in full when sent on PATCH.
parent_id string both No (empty) Yes Parent issue id (same project). Must exist; cannot equal this issue’s id.
blocks array of string both No (none) Yes Ids this issue blocks.
blocked_by array of string both No (none) Yes Ids that block this issue.
sprint_id string both No (empty) Yes Sprint or iteration identifier (convention up to your team).
created_at string both Set by server No RFC3339 creation time.
updated_at string both Set by server No RFC3339 last update time.
created_by string both Current user on create No Clerk user id who created the issue.
updated_by string both Current user on each PATCH No Clerk user id who last updated the issue.
resolved_at string both See Status & timestamps No Set/cleared by the server with status.
closed_at string both See Status & timestamps No Set/cleared by the server with status.

notes is oriented toward stories; the API may still store text for bugs if sent.


Status & timestamps

You normally change status only; the server maintains closure fields.

New status Effect on resolved_at / closed_at
done Both set to now (RFC3339).
cancelled closed_at set to now; resolved_at cleared.
open or in_progress If moving from a terminal state (done / cancelled), both timestamps are cleared.

Statuses are normalized to lowercase on write. Legacy documents with other status values may still appear in lists until updated.


Project summaries (open points)

When the API aggregates open work for a project (e.g. project list), an issue counts toward open points if its status is not done or cancelled. So in_progress items are included.


Examples (JSON)

Create story (minimal)

{ "title": "OAuth login" }

Create bug (with triage)

{
  "title": "Login fails on Safari",
  "severity": "high",
  "description": "Spinner never stops after submit.",
  "steps_to_reproduce": "1. Open Safari …",
  "environment": "Safari 17, macOS",
  "regression": true
}

PATCH (partial)

{ "status": "in_progress", "labels": ["backend", "auth"] }

See also