---
# NOTE: owner=SE from tas.yaml (never change); author=git user per verification-layers.md § 5.1 (fallback=owner)
api_name:
api_slug:
api_version:
spec_source: ""            # YAML-safe string — multiline paths + special chars (§, [, :, etc.) must be quoted (see tas-apitest-plan.md Phase 5.0a)
code_path: ""              # YAML-safe string — quoted always (contains [id], colons, file paths) (see tas-apitest-plan.md Phase 5.0a)
artifact-status: draft   # draft | approved
owner: {se_name}
author:
created_by:
created_date:
updated_date:
feature_id:
framework:                 # execution target — Postman | xUnit | etc. (set at /tas-apitest code-authoring time; design spec is framework-agnostic)
release_id: ""             # optional — set when artifact belongs to a named release (e.g. "R2026-Q3"); used by /tas-release-plan to group outputs
gate_result: ""            # PASS | FAIL — set by Phase 4 when release_id present (per qa/verification-layers.md §6); leave "" for feature-level runs
coverage_percentage: ""    # % endpoints meeting §3.1 minimums — set by Phase 4 when release_id present; leave "" otherwise
---

# API Test Specification: {API Name}

**API Version**: v{api_version}
**Framework**: {framework}
**Created**: [created_date]
**Updated**: [updated_date]
**Status**: [artifact-status] (Draft | Review | Approved | Deprecated)
**Spec Source**: [spec_source]
**Code Path**: [code_path]
**Feature**: [feature_id] (if applicable)

---

## Test Environment & Data

> Design-stage spec lists *what data/environment a TC needs* (base URL per env, test data values, auth). Config schema, HttpClient/TestBase setup-teardown code → `/tas-apitest` (code authoring), not here.

| Environment | BaseUrl | Notes |
|-------------|---------|-------|
| Local | https://localhost:5001 | Development environment |
| Test | https://test-api.example.com | Shared test environment |
| Staging | https://staging-api.example.com | Pre-production |
| Production | https://api.example.com | Smoke tests only |

### Test Data Requirements

| Data Item | Value | Source | Environment-Specific | Notes |
|-----------|-------|--------|---------------------|-------|
| Test User Email | test@example.com | test-data.{env}.json | Yes | Different per env |
| Test User Password | (from secret store) | env var | Yes | NEVER hardcode |
| Auth Token | Generated at runtime | POST /api/auth/token | Yes | Refresh per test class |
| {Entity} ID | {value} | test-data.{env}.json | Yes | Pre-seeded data |

---

## v{N} — Test Cases

### Endpoints Overview

| Method | Path | Description | Auth Required |
|--------|------|-------------|---------------|
| GET | /api/users | List users | Yes |
| POST | /api/users | Create user | Yes |
| GET | /api/users/{id} | Get user by ID | Yes |
| PUT | /api/users/{id} | Update user | Yes |
| DELETE | /api/users/{id} | Delete user | Yes |

### Coverage Matrix

| Endpoint | Happy Path | 401 Unauthorized | 403 Forbidden | 404 Not Found | 400/422 Validation | Business Rule | Priority | Autoable |
|----------|:---------:|:----------------:|:-------------:|:-------------:|:------------------:|:-------------:|:--------:|:--------:|
| GET /api/users | ✓ | ✓ | | | | | P0 | YES |
| POST /api/users | ✓ | ✓ | | | ✓ | | P0 | YES |
| GET /api/users/{id} | ✓ | ✓ | | ✓ | | | P0 | YES |
| PUT /api/users/{id} | ✓ | ✓ | | ✓ | ✓ | | P1 | YES |
| DELETE /api/users/{id} | ✓ | ✓ | ✓ | ✓ | | | P1 | YES |
| POST /api/payments | ✓ | ✓ | | | ✓ | ✓ | P0 | NO (requires Mollie Test Environment) |

**Legend:**
- ✓ = Coverage required
- Priority: P0 (blocks release), P1 (important but not blocking), P2 (nice-to-have) — assign per `qa/test-design.md § Testing Priority Assignment`
- Autoable (API TCs — Contract / Integration / NFR / Backward-compat): **binary YES | NO** per `qa/api-test-strategy.md` — **YES** = assertions complete + Postman-only; **NO** = external tool / human action (e.g. Mollie env, no mock available → per §3.5).
  - **Exception — Security TPs only:** `✅ YES | ⚠️ PARTIAL | ❌ NO` per `qa/security-test-matrix.md § Layer 3` (PARTIAL = Rate Limiting loop script / External API Failure needing Mock Server).

---

### Test Case Details

<!-- TC ID convention: generic → TC-NNN; Feature-linked → {PROJECT}_F{FID}_AC{N}_API_{NNN}_{MOD}. MOD per qa/test-id-convention.md §3: H=happy, E=error, S=security, N=NFR, B=backward-compat. Use Feature-linked format when feature_id is set. Autoable values → see § Coverage Matrix Legend. -->

> **Two exemplars below show the required format** (one Happy with full assertion depth, one Error). Generate the real TC set per `qa/api-test-strategy.md` coverage minimums — do not copy these `/api/users` values.

#### POST /api/users — Create User

##### TC-001: Happy Path — Creates New User
- **Endpoint**: `POST /api/users`
- **Auth**: Required (Bearer token)
- **Preconditions**: Valid auth token; email not already registered
- **Request Body**:
  ```json
  { "email": "newuser@example.com", "name": "New User", "password": "SecurePass123!", "role": "User" }
  ```
- **Expected Response**:
  - Status: 201 Created
  - Body: created user with generated `id`; `Location` header = new resource URL
- **Assertions** (per `qa/istqb-techniques.md § Assertion Depth`):
  - Status 201; `id` valid GUID; `email`/`name`/`role` match request
  - `password` NOT in response (no PII/secret leakage)
  - `Content-Type: application/json`; `Location` header present
  - Follow-up `GET /api/users/{id}` returns the created resource
- **Autoable**: YES (contract assertion complete, Postman-ready)
- **AC Reference**: AC-{N} (if Feature-linked)
- **Test Method Name**: `Post_Users_Returns201_WhenValidRequest`

##### TC-002: Validation — Returns 400 When Email Invalid
- **Endpoint**: `POST /api/users`
- **Auth**: Required
- **Request Body**: `{ "email": "invalid-email", "name": "Test User", "password": "SecurePass123!", "role": "User" }`
- **Expected Response**: 400 Bad Request + validation error body
- **Assertions**:
  - Status 400; error body has machine-readable `code` + human-readable `message` indicating email format
  - No stack trace / internal path exposed (per `qa/error-handling-strategy.md § Error Response Body Contract`)
- **Autoable**: YES (error assertion complete, Postman-ready)
- **AC Reference**: AC-{N} (if Feature-linked)
- **Test Method Name**: `Post_Users_Returns400_WhenEmailInvalid`

##### TC-003: Integration — Handles External Service Timeout
- **Endpoint**: `POST /api/payments`
- **Auth**: Required
- **Preconditions**: External payment service (Mollie) unavailable or timeout
- **Request Body**: `{ "amount": 99.99, "currency": "EUR" }`
- **Expected Response**: 503 Service Unavailable + retry header
- **Assertions**:
  - Status 503; error body indicates external service timeout
  - `Retry-After` header present
- **Autoable**: NO (requires Mollie Test Environment or Mock Server to simulate timeout)
- **AC Reference**: AC-{N} (if Feature-linked)
- **Test Method Name**: `Post_Payments_Returns503_WhenMollieTimeout`

---

## AC Traceability (Optional — Feature-linked only)

> **Not a second TC set.** This is a summary mapping each AC to the TC IDs already defined in § Test Case Details. Anchor TC IDs on AC: `{PROJECT}_F{FEATURE}_AC{N}_API_NNN_{MOD}` (MOD per qa/test-id-convention.md §3).

| AC ID | AC Description | Test Case IDs |
|-------|----------------|---------------|
| AC-1 | {Given...When...Then...} | TC-001, TC-002 |

---

## Cross-Feature Regression Watch (Optional — Feature-linked only)

> TCs in **this** spec that other Features/consumers depend on — if this contract changes, those Features may break. Populated from TestChecklist §1.2.1 (rows marked shared/reused-route) and §5 Risk Registry (shared-contract or breaking-change rows), per `qa/verification-layers.md § 8` traceability. **Scope is narrow — 2 watch types only:**
> - **Shared-Contract** — endpoint/schema reused by ≥2 Features (regression = a change here breaks a sibling Feature)
> - **Backward-Compat** — this version introduces a breaking/versioned change to an existing contract (per `qa/test-design.md § Backward-Compat Applicability Detection`, `bc_applicable = true`)
>
> **Out of scope here** (stays in `## Risk & Coverage Notes` instead): 3rd-party/external API integration risk (operational dependency, not a shared-contract regression), pentest routing, coverage gaps. A row only belongs here if it names **Test Case IDs already defined in this spec** — no TC coverage yet → log as a gap in Risk & Coverage Notes instead, don't add a placeholder row here.

| Watch Type | Contract / Component | Shared By (Features) | Test Case IDs | Inherited From |
|------------|----------------------|----------------------|----------------|-----------------|
| Shared-Contract | `POST /api/example` | Feature-A, Feature-B | TC-009, TC-010 | TestChecklist §1.2.1 |

---

## Risk & Coverage Notes

> Risks found while analysing inputs + coverage that cannot be tested with API tooling here.
> Inherit SE-owned `[TECH-COVERAGE]` (and related) risks from TestChecklist §5 when this spec is Feature-linked.

| Risk ID | Type | Description | Owner | Coverage Gap / Action |
|---------|------|-------------|-------|-----------------------|
| R-001 | [TECH-COVERAGE] | {e.g. heavy load test needs perf infra — not coverable via Postman} | SE/DSE | {note / route} |

---

## Change Log

| Date | Version | Changes | Author |
|------|---------|---------|--------|
| {YYYY-MM-DD} | 1.0 | Initial API test specification | {Git Username} |

---

## AI Usage Log

| # | Date | Command |
|---|------|---------|
| 1 | [created_date] | /tas-apitest-plan |
