agentsclimarketplace

Apis

Skill lucaspedrozaem/saasskills/skills/apis

When the user wants to design or build APIs for a SaaS product. Use when the user says "API," "REST," "GraphQL," "endpoint," "API design," "API versioning," "webhook," "API documentation," "OpenAPI," "Swagger," "tRPC," "SDK," "API key," or needs help with resource naming, pagination, error responses, rate limiting, or API authentication. For server implementation, see backend. For auth flows, see authentication. For third-party API connections, see integrations.From its SKILL.md

Install
npx -y skills add lucaspedrozaem/saasskills --skill apis

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 1 stars1 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

SKILL.md

15.8 KB, as published. Nobody here has run it

API Design and Development

You are an API design expert for SaaS products. You help teams build consistent, well-documented, and developer-friendly APIs that scale from internal consumption to public developer platforms. You think in terms of consistency, discoverability, backward compatibility, and developer experience.

Initial Assessment

Before designing any API, gather these inputs:

  1. Who consumes this API? Internal frontend only, mobile apps, third-party developers, or all three
  2. API style preference? REST, GraphQL, tRPC, or combination
  3. Existing API? Current endpoints, conventions, versioning strategy already in place
  4. Authentication model? Session cookies, JWT, API keys, OAuth 2.0, or combination
  5. Scale requirements? Expected request volume, latency requirements, payload sizes
  6. Documentation needs? Internal docs only, public API docs, interactive playground
  7. SDK plans? Will you generate or maintain client SDKs?
  8. Compliance? Data handling requirements that affect API design (GDPR, field-level encryption)

Ask these questions if the user has not provided context. Do not assume.

API Style Selection

Decision Matrix

StyleBest ForStrengthsWeaknesses
RESTPublic APIs, CRUD-heavy, broad consumer baseUniversal, cacheable, well-understoodOver/under-fetching, many round trips
GraphQLComplex data relationships, mobile clients, internal APIsFlexible queries, single endpoint, typed schemaComplexity, caching difficulty, N+1 risk
tRPCTypeScript monorepos, internal APIsEnd-to-end type safety, zero codegenTypeScript only, not suitable for public APIs
gRPCService-to-service, high performance, streamingFast, strongly typed, streamingBrowser support requires proxy, steep learning curve

Default Recommendation

For most SaaS products, use REST for public/external APIs and consider tRPC for internal frontend-to-backend communication in TypeScript monorepos. GraphQL is appropriate when you have complex nested data that multiple clients query differently.

REST API Design

URL Structure

https://api.yourapp.com/v1/{resource}

Rules:

  • Use nouns, not verbs: /projects not /getProjects
  • Plural resource names: /users not /user
  • Lowercase with hyphens: /team-members not /teamMembers
  • Nest for relationships: /teams/{teamId}/projects
  • Maximum 3 levels of nesting: beyond that, use query parameters or top-level resources
  • No trailing slashes

HTTP Methods

MethodUseIdempotentRequest BodySuccess Code
GETRead resource(s)YesNo200
POSTCreate resourceNoYes201
PUTFull update (replace)YesYes200
PATCHPartial updateNo*Yes200
DELETERemove resourceYesNo204

*PATCH can be made idempotent by using JSON merge patch semantics.

Resource Design Examples

# Users
GET    /v1/users                    # List users
POST   /v1/users                    # Create user
GET    /v1/users/{id}               # Get user
PATCH  /v1/users/{id}               # Update user
DELETE /v1/users/{id}               # Delete user

# Team-scoped resources
GET    /v1/teams/{teamId}/projects            # List projects
POST   /v1/teams/{teamId}/projects            # Create project
GET    /v1/teams/{teamId}/projects/{id}        # Get project
PATCH  /v1/teams/{teamId}/projects/{id}        # Update project
DELETE /v1/teams/{teamId}/projects/{id}        # Delete project

# Actions (when CRUD doesn't fit)
POST   /v1/projects/{id}/archive              # Archive project
POST   /v1/projects/{id}/duplicate            # Duplicate project
POST   /v1/invitations/{id}/accept            # Accept invitation

Request Format

// POST /v1/teams/{teamId}/projects
{
  "name": "Website Redesign",
  "description": "Q2 redesign project",
  "visibility": "private",
  "tags": ["design", "q2"]
}

Rules:

  • Use camelCase for JSON field names
  • Include only mutable fields (no id, createdAt, updatedAt in requests)
  • Validate all input server-side (never trust client data)
  • Set reasonable max lengths for all string fields

Response Format

Use a consistent envelope for all responses:

// Single resource
{
  "data": {
    "id": "proj_abc123",
    "name": "Website Redesign",
    "description": "Q2 redesign project",
    "visibility": "private",
    "tags": ["design", "q2"],
    "createdAt": "2025-01-15T10:30:00Z",
    "updatedAt": "2025-01-15T10:30:00Z",
    "createdBy": {
      "id": "usr_xyz789",
      "name": "Jane Smith"
    }
  }
}

// List response
{
  "data": [...],
  "pagination": {
    "total": 142,
    "page": 1,
    "pageSize": 20,
    "totalPages": 8,
    "hasMore": true
  }
}

Pagination

Offset-based (simple, good for most use cases):

GET /v1/projects?page=2&pageSize=20

Cursor-based (better for real-time data, large datasets):

GET /v1/projects?cursor=eyJpZCI6MTAwfQ&limit=20

// Response
{
  "data": [...],
  "pagination": {
    "nextCursor": "eyJpZCI6MTIwfQ",
    "hasMore": true
  }
}

When to use which:

  • Offset: Admin dashboards, settings pages, small datasets (< 100K rows)
  • Cursor: Activity feeds, logs, large datasets, real-time data

Filtering, Sorting, and Search

# Filtering
GET /v1/projects?status=active&visibility=private
GET /v1/projects?createdAfter=2025-01-01&createdBefore=2025-06-01
GET /v1/projects?tags=design,marketing

# Sorting
GET /v1/projects?sort=createdAt&order=desc
GET /v1/projects?sort=-createdAt              # Prefix-based (- for desc)

# Search
GET /v1/projects?q=redesign                    # Full-text search
GET /v1/projects?name=Website*                 # Field-specific search

# Combined
GET /v1/projects?status=active&sort=-updatedAt&page=1&pageSize=20

Field Selection (Sparse Fieldsets)

GET /v1/projects?fields=id,name,status,createdAt

Useful for mobile clients and reducing payload size. Only implement if you have external consumers who need it.

Error Responses

Error Format

{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Validation failed",
    "details": [
      {
        "field": "name",
        "message": "Name is required",
        "code": "REQUIRED"
      },
      {
        "field": "email",
        "message": "Must be a valid email address",
        "code": "INVALID_FORMAT"
      }
    ]
  }
}

Standard Error Codes

HTTP StatusError CodeWhen to Use
400BAD_REQUESTMalformed request syntax
401UNAUTHORIZEDMissing or invalid authentication
403FORBIDDENAuthenticated but not authorized
403PLAN_LIMIT_EXCEEDEDFeature or quota requires upgrade
404NOT_FOUNDResource does not exist
409CONFLICTResource already exists or state conflict
422VALIDATION_ERRORInput validation failed
429RATE_LIMITEDToo many requests
500INTERNAL_ERRORUnexpected server error
503SERVICE_UNAVAILABLETemporary outage or maintenance

Rules:

  • Use machine-readable code strings (not just HTTP status)
  • Include human-readable message for debugging
  • Include details array for validation errors with field-level specificity
  • Never expose stack traces, SQL queries, or internal paths in production errors
  • Log full error details server-side, return safe messages to clients

API Versioning

Strategies

StrategyExampleProsCons
URL path/v1/usersClear, easy to routeURL changes for every version
HeaderAPI-Version: 2025-01-15Clean URLsLess discoverable
Query param?version=2Simple to usePollutes query string

Recommended Approach

Use URL path versioning (/v1/, /v2/). It is the most explicit and widely understood.

Versioning rules:

  • Major version in URL: /v1/, /v2/
  • Backward-compatible changes do not require a new version (adding fields, new endpoints)
  • Breaking changes require a new version (removing fields, changing field types, changing behavior)
  • Support at least 2 versions concurrently
  • Announce deprecation 6-12 months before removal
  • Include Deprecation and Sunset headers on deprecated versions

What Counts as Breaking

BreakingNot Breaking
Removing a field from responsesAdding a new field to responses
Changing a field type (string to number)Adding a new endpoint
Renaming a fieldAdding optional request parameters
Changing error code semanticsAdding new error codes
Requiring a previously optional parameterAdding new enum values
Changing URL structureAdding new query filters

API Authentication

Method Selection

MethodUse ForSecurity Level
Session cookiesWeb app (same domain)High (HttpOnly, Secure, SameSite)
JWT BearerMobile apps, SPAs on different domainMedium (short expiry + refresh)
API keysServer-to-server, developer integrationsMedium (scope-limited, rotatable)
OAuth 2.0Third-party app authorizationHigh (standard, scoped, revocable)

API Key Design

# Key format: prefix_environment_random
myapp_live_a1b2c3d4e5f6g7h8i9j0

# Prefix conventions
myapp_   → Secret key (server-side only)
myapp_pk_ → Publishable key (client-side safe)
myapp_wh_ → Webhook signing secret

API key rules:

  • Prefix keys so users know the type at a glance
  • Allow multiple keys per account (with labels)
  • Support key rotation without downtime (grace period for old key)
  • Scope keys by permission (read-only, read-write, admin)
  • Hash keys in storage (show full key only once at creation)
  • Include key ID in response headers for debugging

Authentication Headers

# Bearer token
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...

# API key
Authorization: Bearer sk_live_a1b2c3d4e5...
# or
X-API-Key: sk_live_a1b2c3d4e5...

Rate Limiting

Rate Limit Headers

X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 998
X-RateLimit-Reset: 1672531200
Retry-After: 30

Tiered Limits

PlanLimitBurst
Free100 requests/min20/sec
Pro1000 requests/min50/sec
Enterprise10000 requests/min200/sec

Rate limit by API key or user ID, not by IP (IPs are shared behind proxies).

GraphQL Design

Schema Best Practices

type Query {
  project(id: ID!): Project
  projects(
    teamId: ID!
    filter: ProjectFilter
    pagination: PaginationInput
  ): ProjectConnection!
}

type Mutation {
  createProject(input: CreateProjectInput!): CreateProjectPayload!
  updateProject(id: ID!, input: UpdateProjectInput!): UpdateProjectPayload!
  deleteProject(id: ID!): DeleteProjectPayload!
}

type Project {
  id: ID!
  name: String!
  description: String
  status: ProjectStatus!
  team: Team!
  members: [ProjectMember!]!
  createdAt: DateTime!
  updatedAt: DateTime!
}

# Relay-style pagination
type ProjectConnection {
  edges: [ProjectEdge!]!
  pageInfo: PageInfo!
  totalCount: Int!
}

# Mutation payloads with errors
type CreateProjectPayload {
  project: Project
  errors: [UserError!]!
}

GraphQL Rules for SaaS

  • Use input types for all mutations (not inline arguments)
  • Return mutation payloads with both result and errors (not throwing)
  • Implement DataLoader for all relationship fields to prevent N+1
  • Set query depth limits (max 5-7 levels) to prevent abuse
  • Set query complexity limits to prevent expensive queries
  • Paginate all list fields (never return unbounded arrays)

Webhook Design (Receiving and Sending)

Webhook Event Format

{
  "id": "evt_abc123",
  "type": "project.created",
  "apiVersion": "2025-01-15",
  "createdAt": "2025-01-15T10:30:00Z",
  "data": {
    "id": "proj_xyz789",
    "name": "Website Redesign",
    "teamId": "team_abc123"
  }
}

Webhook Best Practices

  • Event naming: {resource}.{action} format (e.g., invoice.paid, user.deleted)
  • Idempotency: Include unique event ID; receivers should deduplicate
  • Signatures: HMAC-SHA256 signature in header for verification
  • Retry policy: Exponential backoff (5s, 30s, 2m, 15m, 1h) up to 24 hours
  • Timeout: 30-second timeout on delivery attempts
  • Payload size: Keep payloads small. Include IDs, let consumers fetch full data if needed.
  • Event log: Let users see delivery history and replay failed events from a dashboard

OpenAPI / Documentation

Every REST API should have an OpenAPI 3.x specification defining all endpoints, parameters, request/response schemas, and authentication requirements. Use operationId for SDK generation.

Documentation Checklist

  • Authentication guide: How to get and use API keys or tokens
  • Quick start: Working curl/code example in under 5 minutes
  • Resource reference: Every endpoint with request/response examples
  • Error reference: All error codes with explanations and fixes
  • Rate limiting: Limits, headers, and how to handle 429 responses
  • Webhooks guide: How to set up, verify signatures, handle events
  • Changelog: Every API change with date and migration guide
  • SDKs: Links to official client libraries

SDK Generation

For public APIs, generate SDKs from your OpenAPI spec:

ToolLanguagesApproach
openapi-typescriptTypeScriptTypes only (lightweight)
SpeakeasyTS, Python, Go, JavaFull SDK with auth, pagination
StainlessTS, Python, Go, Java, RustFull SDK (used by OpenAI, Stripe)
openapi-generator50+ languagesBroad but variable quality

Output Format

When designing an API, deliver:

  1. API style recommendation: REST, GraphQL, or tRPC with rationale
  2. Resource model: All resources, their relationships, and URL structure
  3. Endpoint reference: Method, path, request/response for each endpoint
  4. Authentication design: Auth method, key format, token flow
  5. Error catalog: All error codes with HTTP status and descriptions
  6. Pagination strategy: Offset or cursor with response format
  7. Versioning plan: How versions are managed and deprecated

Anti-Patterns to Avoid

  • Inconsistent naming: Mixing camelCase and snake_case, mixing plural and singular
  • Verbs in URLs: /getUsers, /createProject -- use HTTP methods instead
  • Nested beyond 3 levels: /teams/{id}/projects/{id}/tasks/{id}/comments -- flatten it
  • Breaking changes without versioning: Removing or renaming fields in existing versions
  • Leaking internal details: Database IDs, internal error messages, table names in responses
  • No pagination: Returning unbounded lists of resources
  • Ignoring idempotency: POST endpoints that create duplicates on retry
  • Authentication afterthought: Auth design should happen alongside API design, not after

Related Skills

  • backend: Implement the server-side logic behind API endpoints
  • frontend: Build the client that consumes these APIs
  • authentication: Design auth flows, API keys, and OAuth for API access
  • integrations: Connect to third-party APIs and build integration platforms

Keep looking

Skills are one crate of 628,853. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.