API Reference
Examples API

Examples API

Full REST reference for the examples domain. All routes are under /api/examples, require a Cognito JWT (Authorization: Bearer <token>), and are backed by services/backend/lambda/examples_handler.py / examples_service.py. See specs/api/examples.md in the repo for the underlying spec this page is based on, and the Examples feature guide for the product-level behavior.

Request bodies are snake_case per lk-wiz convention (workspace_id, performance_notes, ...). Query parameters on this domain are camelCase (workspaceId) — the standard lk-wiz split (bodies snake_case, query params camelCase).

⚠️

custom:role is read from the JWT on every route but is never checked — this domain enforces workspace membership only, not role. A viewer can create, edit, and delete examples exactly like an editor or owner.

Endpoints at a glance

MethodPathDescription
POST/api/examplesCreate an example
GET/api/examplesList examples
GET/api/examples/{id}Get an example
PUT/api/examples/{id}Update an example
DELETE/api/examples/{id}Delete an example
POST/api/examples/import-from-post/{id}Import a published post as an example

Create

POST /api/examples
// Request
{
  "workspace_id": "ws_123",
  "title": "How I closed my first enterprise deal",
  "content": "Full post text here...",
  "tags": ["sales", "storytelling"],
  "performance_notes": "50K impressions, 200 comments"
}
// 201 Response
{
  "example_id": "e1e2e3e4-...",
  "workspace_id": "ws_123",
  "title": "How I closed my first enterprise deal",
  "content": "Full post text here...",
  "tags": ["sales", "storytelling"],
  "performance_notes": "50K impressions, 200 comments",
  "created_by": "user_111",
  "created_at": "2026-07-17T12:00:00+00:00",
  "updated_at": "2026-07-17T12:00:00+00:00"
}

workspace_id, title, and content are required (400 if missing or empty after trimming). Validation runs in that order, so an empty title fails before workspace membership is even checked. tags defaults to [], performance_notes to "".

StatusReason
400Missing/empty workspace_id, title, or content
403Caller is not a member of workspace_id

List

GET /api/examples?workspaceId=ws_123
// 200 Response
{ "items": [ /* example objects */ ], "count": 3 }
⚠️

No pagination, tag filter, or sort parameter exists on this endpoint — it's a single DynamoDB GSI1 query returning every example in the workspace in ascending creation-time order (oldest first). There's no ?sort= to reverse that, and a workspace with enough examples to exceed one DynamoDB query page (1 MB) would see results silently truncated.

StatusReason
400Missing workspaceId
403Caller is not a member of workspaceId

Get

GET /api/examples/{id}?workspaceId=ws_123

Returns the example object (same shape as Create's response).

StatusReason
400Missing workspaceId
403Caller is not a member of workspaceId
404No example {id} in that workspace

Update

PUT /api/examples/{id}

Partial update — send only the fields you want to change, plus workspace_id (required for the membership check, not itself persisted as a change).

// Request — retag and update performance notes
{ "workspace_id": "ws_123", "tags": ["sales", "closing"], "performance_notes": "Now at 60K impressions" }
FieldBehavior
titlecoerced to string, stripped, replaces titleno non-emptiness check on update, unlike Create; sending "" clears it
contentcoerced to string, stripped, replaces content — same no-emptiness-check caveat
tagsreplaces tags as-is, no validation
performance_notesreplaces performance_notes as-is

updated_at is always refreshed, even for a body containing no recognized fields. source_post_id (present only on imported examples) cannot be changed through this endpoint.

StatusReason
400Missing workspace_id
403Caller is not a member of workspace_id
404Example not found

Delete

DELETE /api/examples/{id}?workspaceId=ws_123

Any workspace member may delete any example — there is no creator-only or admin-only restriction on this domain (contrast with actions, where delete is creator/admin-only).

StatusReason
200Deleted — { "deleted": true }
400Missing workspaceId
403Caller is not a member of workspaceId
404Example not found

Import from post

POST /api/examples/import-from-post/{id}

{id} in the path is a post id, not an example id.

// Request
{ "workspace_id": "ws_123" }
// 201 Response
{
  "example_id": "e5e6e7e8-...",
  "workspace_id": "ws_123",
  "title": "Why we rebuilt our onboarding flow",
  "content": "Full post text here...",
  "tags": ["product"],
  "performance_notes": "",
  "source_post_id": "post_789",
  "created_by": "user_111",
  "created_at": "2026-07-17T12:00:00+00:00",
  "updated_at": "2026-07-17T12:00:00+00:00"
}

The source post must exist and have status: "published" — anything else (draft, in review, scheduled) is rejected with 409. title, content, and tags are copied from the post; performance_notes always starts empty (never copied from the post, even if the post has performance data recorded elsewhere); source_post_id is set to the post's id and is the one field that distinguishes an imported example from a manually-created one.

StatusReason
400Missing workspace_id
403Caller is not a member of workspace_id
404No post {id} in that workspace
409Post exists but is not published