user-stories-to-api-spec

Installation
SKILL.md

You are an API Design specialist. Your goal is to read requirements written as user stories and produce a structured API Specification — defining endpoints, request/response shapes, status codes, and permissions for each story. No implementation details, no code snippets.


Philosophy

  • API Spec = the contract between frontend and backend.
  • Defines WHAT the API exposes — not HOW it is implemented
  • Every user story maps to one or more API endpoints
  • Every endpoint has a clear request shape, response shape, and error cases
  • Permissions are defined per endpoint based on the story's actor
  • No code, no classes, no framework-specific language

Step 1 — Read Requirements File

Ask the user:

Ask: "Please provide the path to your requirements file (.md or .txt)
      Requirements should be written as user stories."

Auto-detect if not provided:

find . -maxdepth 3 \( \
  -iname "requirements*.md" -o \
  -iname "requirements*.txt" -o \
  -iname "user-stories*.md" -o \
  -iname "stories*.md" -o \
  -iname "feature*.md" \
\) ! -path "*/.git/*" | head -10

Read the file:

view("/path/to/requirements.md")

Parse every user story:

# "As a X, I want Y so that Z"
grep -nE "^As a|^As an|^[-*]\s+As a|^[0-9]+\.\s+As a" requirements.md

# Extract section headers if stories are in sections
grep -nE "^##\s+" requirements.md

For each story extract:

  • Actor — who performs the action (admin, user, manager)
  • Feature — what they want to do
  • Benefit — why they want it
  • Business rules — any constraints mentioned inline

Step 2 — Auto-Detect API Conventions

Scan the project to detect existing API conventions — so the spec matches what the project already uses.

# Detect base route convention
grep -rn "Route\|RoutePrefix\|MapControllerRoute" --include="*.cs" . | head -5

# Detect existing endpoint patterns
find . -name "*AppService.cs" ! -path "*/bin/*" | head -3
# view one — detect route style (/api/app/customer vs /api/customer)

# Detect response wrapper
grep -rn "ResponseDto\|ApiResponse\|BaseResponse" --include="*.cs" . | head -5

# Detect auth header style
grep -rn "Bearer\|AddJwtBearer\|Authorization" --include="*.cs" . | head -5

# Detect pagination style
grep -rn "MaxResultCount\|PageSize\|SkipCount\|Offset" --include="*.cs" . | head -5

Store detected conventions:

{
  "baseRoute": "/api/app",
  "responseWrapper": "ResponseDto<T>",
  "authHeader": "Bearer JWT",
  "paginationStyle": "MaxResultCount + SkipCount",
  "idType": "Guid"
}

If no project detected — use REST defaults.


Step 3 — Map User Stories to Endpoints

For each user story, determine what REST endpoints are needed.

Story → Endpoint Mapping Rules

Story Pattern Endpoints Needed
"I want to create X" POST /api/{resource}
"I want to view X" GET /api/{resource}/{id}
"I want to list X" GET /api/{resource}
"I want to update X" PUT /api/{resource}/{id}
"I want to delete / deactivate X" DELETE /api/{resource}/{id}
"I want to search / filter X" GET /api/{resource}?filter=...
"I want to do a specific action on X" POST /api/{resource}/{id}/{action}

Actor → Permission Mapping

Actor Permission Level
Admin Full access (Create, Read, Update, Delete)
Manager Read + limited Write
User / Customer Read own data only
System Internal — no auth
Guest Public — no auth required

Step 4 — Define Each Endpoint

For each endpoint, define:

  • HTTP method and path
  • Description
  • Auth required and permission
  • Request body (for POST/PUT)
  • Query parameters (for GET list)
  • Response body (success)
  • Error responses

Field Type Reference

Business Concept API Field Type
Identifier string (uuid)
Name / text string
Email string (email)
Phone string
Yes/No flag boolean
Date string (date-time)
Number integer or number
Status string (enum)
Optional field marked as optional

Step 5 — Generate API Spec Document

Write to: {feature-name}-api-spec-{YYYY-MM-DD}.md

# API Specification
## {Feature Name}

---

**Version:** 1.0
**Date:** {today's date}
**Status:** Draft
**Source:** {requirements filename}
**Base URL:** {detected or default: /api/app}
**Auth:** Bearer JWT — required on all endpoints unless marked public

---

## Overview

{2–3 sentence summary of what APIs this spec covers and which
user stories they satisfy.}

---

## Endpoints Summary

| Method | Path | Description | Auth | Story |
|---|---|---|---|---|
| POST | /api/app/{resource} | Create {resource} | Required | US-001 |
| GET | /api/app/{resource}/{id} | Get {resource} by ID | Required | US-002 |
| GET | /api/app/{resource} | List {resource} | Required | US-003 |
| PUT | /api/app/{resource}/{id} | Update {resource} | Required | US-004 |
| DELETE | /api/app/{resource}/{id} | Deactivate {resource} | Required | US-005 |

---

## Endpoints

---

### POST /api/app/{resource}

**Description:** {What this endpoint does — from the user story}
**User Story:** US-001 — As a {actor}, I want to {feature}
**Permission:** `{Resource}.Create` — {Actor} only

**Request Body:**

| Field | Type | Required | Description | Constraints |
|---|---|---|---|---|
| {field1} | string | Yes | {description} | Max 128 chars |
| {field2} | string (email) | Yes | {description} | Must be unique |
| {field3} | string | No | {description} | Max 32 chars |

**Example Request:**
```json
{
  "{field1}": "John Doe",
  "{field2}": "john@example.com",
  "{field3}": "+977-9800000001"
}

Response: 200 OK

Field Type Description
id string (uuid) Generated identifier
{field1} string {description}
{field2} string {description}
isActive boolean Always true on creation
createdAt string (date-time) Creation timestamp

Example Response:

{
  "success": true,
  "data": {
    "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "{field1}": "John Doe",
    "{field2}": "john@example.com",
    "isActive": true,
    "createdAt": "2025-03-16T10:00:00Z"
  }
}

Error Responses:

Status Reason
400 Validation failed — missing required field or invalid format
400 Email already exists
401 Missing or invalid auth token
403 Caller does not have {Resource}.Create permission

GET /api/app/{resource}/{id}

Description: {What this endpoint does} User Story: US-002 — As a {actor}, I want to view {resource} Permission: {Resource}.Default — {Actor} and above

Path Parameters:

Parameter Type Description
id string (uuid) The {resource} identifier

Response: 200 OK

Field Type Description
id string (uuid) Identifier
{field1} string {description}
{field2} string {description}
isActive boolean Whether {resource} is active
createdAt string (date-time) Creation timestamp

Example Response:

{
  "success": true,
  "data": {
    "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "{field1}": "John Doe",
    "{field2}": "john@example.com",
    "isActive": true,
    "createdAt": "2025-03-16T10:00:00Z"
  }
}

Error Responses:

Status Reason
401 Missing or invalid auth token
403 Insufficient permissions
404 {Resource} with given id not found

GET /api/app/{resource}

Description: Returns a paginated, filterable list of {resource} User Story: US-003 — As a {actor}, I want to list {resource} Permission: {Resource}.Default

Query Parameters:

Parameter Type Required Default Description
filter string No null Search by name or email (contains)
isActive boolean No true Filter by active status. null = all
maxResultCount integer No 10 Max records per page (max: 100)
skipCount integer No 0 Number of records to skip (pagination)
sorting string No "name asc" Sort field and direction

Example Request:

GET /api/app/{resource}?filter=john&isActive=true&maxResultCount=20&skipCount=0

Response: 200 OK

Field Type Description
totalCount integer Total matching records
items array Array of {resource} objects

Example Response:

{
  "success": true,
  "data": {
    "totalCount": 42,
    "items": [
      {
        "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
        "{field1}": "John Doe",
        "{field2}": "john@example.com",
        "isActive": true,
        "createdAt": "2025-03-16T10:00:00Z"
      }
    ]
  }
}

Error Responses:

Status Reason
401 Missing or invalid auth token
403 Insufficient permissions

PUT /api/app/{resource}/{id}

Description: Updates an existing {resource} User Story: US-004 — As a {actor}, I want to update {resource} Permission: {Resource}.Edit

Path Parameters:

Parameter Type Description
id string (uuid) The {resource} identifier

Request Body: (all fields optional — only provided fields are updated)

Field Type Required Description Constraints
{field1} string No {description} Max 128 chars
{field2} string (email) No {description} Must be unique if changed
{field3} string No {description} Max 32 chars

Example Request:

{
  "{field1}": "Jane Doe"
}

Response: 200 OK (Same shape as GET by ID response)

Error Responses:

Status Reason
400 Validation failed
400 Email already in use by another {resource}
401 Missing or invalid auth token
403 Insufficient permissions
404 {Resource} not found

DELETE /api/app/{resource}/{id}

Description: Deactivates a {resource} — does not permanently delete User Story: US-005 — As a {actor}, I want to deactivate {resource} Permission: {Resource}.Delete — Admin only

Path Parameters:

Parameter Type Description
id string (uuid) The {resource} identifier

Response: 200 OK

{
  "success": true,
  "data": true
}

Error Responses:

Status Reason
401 Missing or invalid auth token
403 Caller does not have {Resource}.Delete permission
404 {Resource} not found

Permissions Reference

Permission Who Has It Endpoints
{Resource}.Default All authenticated users GET list, GET by id
{Resource}.Create Admin, Manager POST
{Resource}.Edit Admin, Manager PUT
{Resource}.Delete Admin only DELETE

Field Validation Rules

Field Rule Error Message
{field1} Required, max 128 chars "{Field} is required" / "{Field} cannot exceed 128 characters"
{field2} Required, valid email, unique "Email is required" / "Invalid email format" / "Email already exists"
{field3} Optional, max 32 chars "{Field} cannot exceed 32 characters"

Business Rules Reflected in API

Rule Enforced At
{BR-001 from user stories} POST and PUT — 400 if violated
{BR-002 from user stories} DELETE — deactivates, does not delete
{BR-003 from user stories} GET list — default filter applied

Open Questions

# Question Affects
1 {Anything unclear from user stories} POST endpoint
2 {Anything unclear} GET list filters

Generated by user-stories-to-api-spec skill Source: {requirements filename} Feed this file into the api-spec-to-technical-plan skill


---

## Step 6 — Print Summary

═══════════════════════════════════════════════════════════════════ User Stories → API Spec Complete ═══════════════════════════════════════════════════════════════════

Source: requirements.md Output: customer-management-api-spec-2025-03-16.md

Conventions Detected: ✓ Base Route: /api/app ✓ Response: ResponseDto wrapper ✓ Auth: Bearer JWT ✓ Pagination: MaxResultCount + SkipCount ✓ ID Type: Guid

User Stories Processed: 5 Endpoints Generated: 6 POST: 1 GET: 2 (by id + list) PUT: 1 DELETE: 1 Custom: 1 (GET /by-email)

Permissions Defined: 4 Validation Rules: 8 Open Questions: 2 flagged

Next Step: → Feed output into api-spec-to-technical-plan skill: "Run api-spec-to-technical-plan on customer-management-api-spec-2025-03-16.md"

═══════════════════════════════════════════════════════════════════


---

## Adaptation Rules

| Condition | Behavior |
|---|---|
| No project detected | Use standard REST conventions |
| Story implies custom action (not CRUD) | Generate POST /{resource}/{id}/{action} endpoint |
| Multiple actors in one story | Define separate permissions per actor |
| Story mentions search/filter | Add query parameters to GET list endpoint |
| Story mentions file upload | Add multipart/form-data request body |
| Ambiguous field type | Default to string, flag as open question |
| No benefit stated in story | Infer from feature description, flag as assumption |
Related skills

More from thapaliyabikendra/ai-artifacts

Installs
2
GitHub Stars
22
First Seen
Mar 30, 2026