For most cases, having an LLM write your spec is faster and produces equally good results. Manual authoring makes sense when you want precise control, are learning the format, or don't have LLM access.
The structure
Every MAPI document has three parts:
- Document header — Title, description, and metadata
- Global types (optional) — Shared TypeScript interfaces
- Capabilities — One section per API operation
The Author Reference Card has the complete format. Keep it open as you write.
MAPI Author Reference Card
Complete format reference — skeletons, patterns, and examples
Or paste this prompt directly into your LLM chat
Document header
Start with a title (H1), description, and metadata block:
# Your API Name A clear description of what this API does and who it's for. One to three sentences is usually enough. version: 1.0.0 base_url: https://api.example.com/v1 auth: bearer
| Field | Required | Values |
|---|---|---|
version |
Yes | Semantic version (e.g., 1.0.0) |
base_url |
Yes | Root URL for all endpoints |
auth |
Yes | bearer, api_key, basic, oauth2, none |
Capabilities
Each API operation is a capability. Separate them with ---:
--- ## Capability: Create User id: users.create transport: HTTP POST /users ### Intention Create a new user account. Use this when onboarding a new customer. The email must be unique; attempting to create a duplicate returns 409. ### Logic Constraints - Email addresses are case-insensitive and normalized to lowercase - Password must be at least 8 characters with one number - If `send_welcome_email` is true, an email is queued (not sent synchronously) ### Input ```typescript interface CreateUserRequest { email: string; // required, format: email password: string; // required, length: 8-128 name?: string; // length: 1-100 send_welcome_email?: boolean; // default: true } ``` ### Output ```typescript interface User { id: string; email: string; name: string | null; created_at: string; // ISO 8601 } ``` ```typescript interface ConflictError { error: 'email_exists'; message: string; } ``` > Errors: standard (400, 401, 429, 500)
Transport strings
| Pattern | Meaning |
|---|---|
HTTP GET /path |
GET request |
HTTP POST /path |
POST request |
HTTP GET /path/{id} |
Path parameter |
HTTP POST /path (SSE) |
Server-Sent Events stream |
WS /path |
WebSocket |
INTERNAL |
Client-side only, no network |
Constraint comments
Add constraints as TypeScript comments:
| Pattern | Example |
|---|---|
// required |
name: string; // required |
// range: min-max |
age: number; // range: 0-150 |
// length: min-max |
title: string; // length: 1-200 |
// default: value |
page?: number; // default: 1 |
// format: type |
email: string; // format: email |
Don't just describe what the endpoint does—explain when to use it and why. "Creates a user" is useless. "Create a new user account during customer onboarding. Email must be unique." tells the reader (human or LLM) what they need to know.
Validate your work
After writing, run your spec through validation to catch structural issues before they cause problems.