API integrations are the leading source of security vulnerabilities and production bugs in modern web applications. OWASP API Security Top 10 lists broken authentication, excessive data exposure, and rate limiting failures as the most critical API risks. This checklist covers security, error handling, testing, and documentation for every API integration.
On this page
Security Checklist
Never expose API keys in client-side code
API keys in JavaScript source code, git commits, or console logs are a critical security vulnerability. All API calls requiring secrets must be made server-side or via a secure proxy.
Authentication Methods Comparison
| Method | Use Case | Security Level | Token Expiry | Implementation Complexity |
|---|---|---|---|---|
| API Key | Server-to-server, simple integrations | Medium | Long-lived (weeks/months) | Simple — single header or query param |
| OAuth 2.0 (Client Credentials) | Machine-to-machine, server apps | High | Short-lived tokens (minutes/hours) | Medium — client_id + client_secret exchange |
| OAuth 2.0 (Authorization Code) | On behalf of users, social login | High | Access token + refresh token pattern | Complex — multi-step flow, PKCE recommended |
| JWT (Bearer token) | Stateless API authentication | High (if implemented correctly) | Configurable, typically 15min–24h | Medium — ensure RS256 signing, verify audience/issuer |
| Mutual TLS (mTLS) | Zero-trust, high-security API access | Very High | Certificate-based (months/years) | Complex — PKI setup required |
| HMAC Signatures | Webhook validation, request signing | High | Timestamp-based (typically 5 min window) | Medium — compute HMAC-SHA256, compare signatures |
API Key
- Use Case
- Server-to-server, simple integrations
- Security Level
- Medium
- Token Expiry
- Long-lived (weeks/months)
- Implementation Complexity
- Simple — single header or query param
OAuth 2.0 (Client Credentials)
- Use Case
- Machine-to-machine, server apps
- Security Level
- High
- Token Expiry
- Short-lived tokens (minutes/hours)
- Implementation Complexity
- Medium — client_id + client_secret exchange
OAuth 2.0 (Authorization Code)
- Use Case
- On behalf of users, social login
- Security Level
- High
- Token Expiry
- Access token + refresh token pattern
- Implementation Complexity
- Complex — multi-step flow, PKCE recommended
JWT (Bearer token)
- Use Case
- Stateless API authentication
- Security Level
- High (if implemented correctly)
- Token Expiry
- Configurable, typically 15min–24h
- Implementation Complexity
- Medium — ensure RS256 signing, verify audience/issuer
Mutual TLS (mTLS)
- Use Case
- Zero-trust, high-security API access
- Security Level
- Very High
- Token Expiry
- Certificate-based (months/years)
- Implementation Complexity
- Complex — PKI setup required
HMAC Signatures
- Use Case
- Webhook validation, request signing
- Security Level
- High
- Token Expiry
- Timestamp-based (typically 5 min window)
- Implementation Complexity
- Medium — compute HMAC-SHA256, compare signatures
Error Handling Standards
| HTTP Status | Meaning | Retry? | Standard Response Format |
|---|---|---|---|
| 200 OK | Success | N/A | { "data": {...} } |
| 201 Created | Resource created | N/A | { "data": {...}, "id": "abc123" } |
| 400 Bad Request | Client sent invalid data | No | { "error": "VALIDATION_FAILED", "message": "...", "fields": [...] } |
| 401 Unauthorized | Auth token missing or invalid | No (re-auth) | { "error": "UNAUTHORIZED", "message": "Authentication required" } |
| 403 Forbidden | Authenticated but not permitted | No | { "error": "FORBIDDEN", "message": "Insufficient permissions" } |
| 404 Not Found | Resource doesn't exist | No | { "error": "NOT_FOUND", "message": "Resource not found" } |
| 429 Too Many Requests | Rate limit exceeded | Yes — with backoff | { "error": "RATE_LIMITED", "retryAfter": 60 } |
| 500 Internal Server Error | Server error (not client's fault) | Yes — limited retries | { "error": "INTERNAL_ERROR", "message": "An error occurred. Please try again." } |
| 503 Service Unavailable | Downstream service down | Yes — with backoff | { "error": "SERVICE_UNAVAILABLE", "message": "Service temporarily unavailable" } |
200 OK
- Meaning
- Success
- Retry?
- N/A
- Standard Response Format
- { "data": {...} }
201 Created
- Meaning
- Resource created
- Retry?
- N/A
- Standard Response Format
- { "data": {...}, "id": "abc123" }
400 Bad Request
- Meaning
- Client sent invalid data
- Retry?
- No
- Standard Response Format
- { "error": "VALIDATION_FAILED", "message": "...", "fields": [...] }
401 Unauthorized
- Meaning
- Auth token missing or invalid
- Retry?
- No (re-auth)
- Standard Response Format
- { "error": "UNAUTHORIZED", "message": "Authentication required" }
403 Forbidden
- Meaning
- Authenticated but not permitted
- Retry?
- No
- Standard Response Format
- { "error": "FORBIDDEN", "message": "Insufficient permissions" }
404 Not Found
- Meaning
- Resource doesn't exist
- Retry?
- No
- Standard Response Format
- { "error": "NOT_FOUND", "message": "Resource not found" }
429 Too Many Requests
- Meaning
- Rate limit exceeded
- Retry?
- Yes — with backoff
- Standard Response Format
- { "error": "RATE_LIMITED", "retryAfter": 60 }
500 Internal Server Error
- Meaning
- Server error (not client's fault)
- Retry?
- Yes — limited retries
- Standard Response Format
- { "error": "INTERNAL_ERROR", "message": "An error occurred. Please try again." }
503 Service Unavailable
- Meaning
- Downstream service down
- Retry?
- Yes — with backoff
- Standard Response Format
- { "error": "SERVICE_UNAVAILABLE", "message": "Service temporarily unavailable" }