user-stories-to-api-spec
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 |
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 |
More from thapaliyabikendra/ai-artifacts
abp-infrastructure-patterns
ABP Framework cross-cutting patterns including authorization, background jobs, distributed events, multi-tenancy, and module configuration. Use when: (1) defining permissions, (2) creating background jobs, (3) publishing/handling distributed events, (4) configuring modules.
59clean-code-dotnet
Clean Code principles adapted for C#/.NET including naming, variables, functions, SOLID, error handling, and async patterns. Use when: (1) reviewing C# code, (2) refactoring for clarity, (3) writing new code, (4) code review feedback.
52abp-entity-patterns
ABP Framework domain layer patterns including entities, aggregates, repositories, domain services, and data seeding. Use when: (1) creating entities with proper base classes, (2) implementing custom repositories, (3) writing domain services, (4) seeding data.
51abp-api-implementation
Implement REST APIs in ABP Framework with AppServices, DTOs, pagination, filtering, and authorization. Use when building API endpoints for ABP applications.
46abp-service-patterns
ABP Framework application layer patterns including AppServices, DTOs, Mapperly mapping, Unit of Work, and common patterns like Filter DTOs and ResponseModel. Use when: (1) creating AppServices, (2) mapping DTOs with Mapperly, (3) implementing list filtering, (4) wrapping API responses.
44abp-contract-scaffolding
Generate ABP Application.Contracts layer scaffolding (interfaces, DTOs, permissions) from technical design. Enables parallel development by abp-developer and qa-engineer. Use when: (1) backend-architect needs to generate contracts, (2) preparing for parallel implementation workflow, (3) creating API contracts before implementation.
36