API Versioning Strategies: Complete Guide for REST & GraphQL APIs (2026)
π‘ Monitor your APIs β know when they go down before your users do
Better Stack checks uptime every 30 seconds with instant Slack, email & SMS alerts. Free tier available.
Affiliate link β we may earn a commission at no extra cost to you
API versioning is one of the most critical decisions in API design. Get it wrong, and you'll break client applications, lose developer trust, and spend months managing painful migrations. This guide covers everything from choosing the right versioning strategy to implementing deprecation workflowsβwith real-world examples from Stripe, GitHub, AWS, and other industry leaders.
What Is API Versioning?
API versioning is the practice of managing changes to an API by creating distinct versions that allow developers to upgrade at their own pace. Without versioning, every API change would potentially break existing client applications.
Think of it like software versioning (iOS 17 vs iOS 16), but for APIs. Different clients can use different versions simultaneously while you roll out improvements, bug fixes, or breaking changes.
π― Key Concept
API versioning is a contract between API provider and consumer. Once you publish v1, you're committing to support it until you explicitly deprecate it. This gives developers stability and predictability.
A Simple Example
// v1: Original endpoint
GET /api/v1/users
Response: { "id": 123, "name": "Alice" }
// v2: Breaking change - added email requirement
GET /api/v2/users
Response: { "id": 123, "full_name": "Alice Smith", "email": "alice@example.com" }
// Both versions can coexist!
// Old clients continue using v1 (no breaking changes)
// New clients adopt v2 (better data model)Why Versioning Matters
1. Prevents Breaking Changes
Without versioning, fixing a bug or adding a field could break thousands of production applications. Versioning lets you introduce changes safely.
β οΈ Real-World Disaster
In 2019, a payment API changed their error response format without versioning. 7,800+ merchant applications broke overnight. Customer support was flooded with tickets. The company had to emergency rollback and lost $2.1M in churn.
2. Enables Gradual Migration
Enterprise clients can't always upgrade instantly. Versioning gives them months (or years) to migrate on their schedule.
3. Supports Multiple Client Types
Mobile apps (slow update cycles), web apps (frequent updates), and server-to-server integrations (conservative upgrades) can all use different versions.
4. Builds Developer Trust
Developers trust APIs that don't break unexpectedly. Good versioning practices signal professionalism and reliability.
β Success Story: Stripe
Stripe maintains 10+ API versions simultaneously (dating back to 2011). Developers can pin to a version and upgrade only when ready. This is why Stripe has 99.99% uptime and excellent developer satisfaction.
The 5 Main Versioning Strategies
There are 5 common ways to version REST APIs, each with trade-offs:
| Strategy | Example | Pros | Cons | Who Uses It |
|---|---|---|---|---|
| URI Path | /v1/users | Simple, visible, cacheable | URI pollution | Stripe, Twilio, Twitter |
| Query Parameter | /users?version=2 | Clean URIs, optional | Less discoverable, cache issues | Netflix |
| Custom Header | X-API-Version: 2 | Clean URIs, RESTful | Hidden, harder to test | Microsoft Azure, GitHub (dates) |
| Accept Header | Accept: application/vnd.api+json;v=2 | RESTful, content negotiation | Complex, poor tooling support | GitHub (old) |
| Subdomain | v2.api.example.com | Clear separation, independent deploys | Infrastructure overhead, CORS | Salesforce |
Recommendation: For most APIs, URI path versioning (/v1/, /v2/) is the best choice. It's simple, explicit, and supported by all HTTP tools.
URI Path Versioning (Most Common)
The most popular approach: put the version number in the URL path.
GET https://api.stripe.com/v1/charges
GET https://api.twilio.com/2010-04-01/Accounts
GET https://api.twitter.com/2/tweetsImplementation in Express.js
import express from 'express';
const app = express();
// v1 routes
app.get('/api/v1/users', (req, res) => {
res.json({
id: 123,
name: 'Alice' // Old format
});
});
// v2 routes - breaking change!
app.get('/api/v2/users', (req, res) => {
res.json({
id: 123,
full_name: 'Alice Smith', // Changed field name
email: 'alice@example.com' // Added required field
});
});
// Both versions coexist
app.listen(3000);Pros
- β Explicit and visible - version is obvious in every request
- β Easy to test - just change the URL in Postman/curl
- β Cacheable - CDNs and proxies can cache by URL
- β Routing-friendly - easy to route to different codebases
- β Documentation-friendly - clear separation in docs
Cons
- β URI pollution - version in every endpoint
- β Not RESTful purist - URLs should represent resources, not versions
- β Migration overhead - clients must update all URLs
When to Use
Use URI path versioning when:
- π― You're building a public API for external developers
- π― Simplicity and discoverability matter
- π― You want version-specific monitoring/logging
- π― You might deploy different versions to different servers
Query Parameter Versioning
Put the version in a query parameter:
GET /api/users?version=1
GET /api/users?version=2
GET /api/users?v=2 // Shorter aliasImplementation
app.get('/api/users', (req, res) => {
const version = req.query.version || req.query.v || '1'; // Default to v1
if (version === '2') {
res.json({
id: 123,
full_name: 'Alice Smith',
email: 'alice@example.com'
});
} else {
res.json({
id: 123,
name: 'Alice'
});
}
});Pros
- β Clean URIs - base path stays the same
- β Optional parameter - can default to latest or v1
- β Easy to add - no routing changes needed
Cons
- β Cache invalidation issues - some proxies ignore query params
- β Less discoverable - not obvious from the URL structure
- β Can be forgotten - easy to omit in requests
When to Use
Use query parameter versioning when:
- π― You want clean base URLs
- π― You're adding versioning to an existing API
- π― You want to make version optional with a default
β οΈ Cache Warning
Some CDNs and proxies strip query parameters or don't use them for cache keys. Make sure your caching layer respects the version parameter!
Custom Header Versioning
Use a custom HTTP header to specify the version:
GET /api/users
X-API-Version: 2
# Or date-based (GitHub style)
GET /api/users
X-GitHub-Api-Version: 2026-03-01Implementation
app.get('/api/users', (req, res) => {
const version = req.headers['x-api-version'] || '1';
if (version === '2') {
res.json({ id: 123, full_name: 'Alice Smith', email: 'alice@example.com' });
} else {
res.json({ id: 123, name: 'Alice' });
}
});Real-World Example: GitHub Date-Based Versioning
GitHub uses date-based versioning in headers:
curl https://api.github.com/users/octocat \
-H "X-GitHub-Api-Version: 2026-03-01"
# This locks the client to the API behavior as of March 1, 2026Why date-based? GitHub can make small improvements continuously without bumping major versions. Clients pin to a date and get a stable snapshot.
Pros
- β Clean URIs - no version in the path
- β RESTful - URLs represent resources, headers handle metadata
- β Flexible - can use semantic versions, dates, or custom schemes
Cons
- β Hidden - not obvious from URL
- β Harder to test - must set headers in every tool
- β Documentation overhead - requires explicit header instructions
- β Cache complexity - must configure
Vary: X-API-Version
When to Use
Use custom header versioning when:
- π― You want truly RESTful URIs
- π― Your clients are sophisticated (servers, not browsers)
- π― You want date-based or custom versioning schemes
Accept Header Versioning (Content Negotiation)
Use the standard Accept header for content negotiation:
GET /api/users
Accept: application/vnd.myapi.v2+json
# Or simpler vendor MIME type
GET /api/users
Accept: application/vnd.myapi+json;version=2Implementation
app.get('/api/users', (req, res) => {
const accept = req.headers.accept || '';
if (accept.includes('v2') || accept.includes('version=2')) {
res.type('application/vnd.myapi.v2+json');
res.json({ id: 123, full_name: 'Alice Smith', email: 'alice@example.com' });
} else {
res.type('application/vnd.myapi.v1+json');
res.json({ id: 123, name: 'Alice' });
}
});Pros
- β HTTP standard - uses content negotiation correctly
- β Clean URIs - no version in path
- β Semantically correct - different versions = different representations
Cons
- β Complex - vendor MIME types are hard to understand
- β Poor tooling - many tools don't support custom MIME types well
- β Browser unfriendly - can't test in browser address bar
- β Debugging difficulty - harder to see what version failed
When to Use
Use Accept header versioning when:
- π― You're a REST purist following HTTP specs strictly
- π― Your API returns different media types (XML, JSON, Protocol Buffers)
- π― You want academic correctness over pragmatism
Reality check: Almost nobody uses this approach anymore. Even GitHub (who used to) switched to custom headers. URI path versioning is far more practical.
Subdomain Versioning
Use different subdomains for different versions:
https://api.example.com/users # v1 (default)
https://v2.api.example.com/users # v2
https://v3.api.example.com/users # v3Real-World Example: Salesforce
Salesforce uses subdomains for different API families:
https://login.salesforce.com # Authentication
https://na1.salesforce.com/services/data/v56.0 # Data API v56
https://na1.salesforce.com/services/data/v57.0 # Data API v57Pros
- β Complete isolation - different servers, databases, code
- β Independent scaling - scale v1 and v2 separately
- β Blue-green deployments - easy to roll out v2 gradually
- β Clear separation - no shared routing logic
Cons
- β Infrastructure overhead - separate DNS, SSL certs, load balancers
- β CORS complexity - cross-origin requests between versions
- β Cost - running multiple production environments
- β Maintenance burden - patching vulnerabilities across versions
When to Use
Use subdomain versioning when:
- π― You need complete physical isolation (security, compliance)
- π― Different versions have vastly different infrastructure needs
- π― You're a large enterprise with dedicated DevOps resources
- π― You're doing a major rewrite (v2 is completely new codebase)
Semantic Versioning for APIs
Should you use semantic versioning (MAJOR.MINOR.PATCH) for APIs?
The Semver Format
MAJOR.MINOR.PATCH
MAJOR: Breaking changes (v1 β v2)
MINOR: New features, backward compatible (v1.0 β v1.1)
PATCH: Bug fixes, backward compatible (v1.0.0 β v1.0.1)
Examples:
/api/v1.2.3/users # Full semver
/api/v1/users # Major version only (recommended)Recommendation: Major Version Only
For most APIs, expose only the MAJOR version publicly:
β
Good: /api/v1/users
β
Good: /api/v2/users
β Avoid: /api/v1.2.3/users # Too granular
β Avoid: /api/v1.2/users # Clients don't care about MINORWhy Major Version Only?
- π Simplicity: Clients only care about breaking changes
- π Flexibility: You can add features and fix bugs without client updates
- π Less noise: No version churn (v1.1 β v1.2 β v1.3)
- π Industry standard: Stripe, GitHub, AWS all use major versions only
When to Use Full Semver
Use MAJOR.MINOR versioning when:
- π― You're building SDK libraries (not HTTP APIs)
- π― Clients need fine-grained control over features
- π― You're versioning internal microservices
β Stripe's Hybrid Approach
Stripe uses date-based versions publicly (2026-03-01) but tracks internal semver for features. Best of both worlds: clients get stability, Stripe gets flexibility.
Manage API keys across versions securely
Multiple API versions mean multiple sets of credentials. Use 1Password to organize and rotate secrets per version β never lose track of active keys.
Try 1Password Free βBreaking vs Non-Breaking Changes
The #1 rule of API versioning: Don't break existing clients.
Breaking Changes (Require Version Bump)
β Removing a field
v1: { "name": "Alice" }
v2: { "full_name": "Alice" } // "name" removed!
β Renaming a field
v1: { "user_id": 123 }
v2: { "id": 123 } // Renamed!
β Changing data types
v1: { "created_at": 1646611200 } // Unix timestamp
v2: { "created_at": "2026-03-09T20:00:00Z" } // ISO string
β Making optional field required
v1: POST /users { "name": "Alice" } // email optional
v2: POST /users { "name": "Alice", "email": "..." } // email required!
β Changing error response format
v1: { "error": "Not found" }
v2: { "errors": [{ "code": "NOT_FOUND", "message": "..." }] }
β Removing an endpoint
v1: DELETE /api/users/:id
v2: (endpoint removed)
β Changing status codes
v1: Returns 404 for missing user
v2: Returns 410 for missing user
β Changing authentication method
v1: API key in query param
v2: Bearer token in headerNon-Breaking Changes (Safe Without Version Bump)
β
Adding new optional fields
v1: { "name": "Alice" }
v1: { "name": "Alice", "email": "alice@example.com" } // Safe!
β
Adding new endpoints
v1: GET /users
v1: GET /users/:id/orders // New endpoint, safe
β
Adding new optional query parameters
v1: GET /users
v1: GET /users?include_inactive=true // Optional param, safe
β
Relaxing validation (making required field optional)
v1: POST /users requires email
v1: POST /users email now optional // Safe (more permissive)
β
Adding new error codes (keeping existing ones)
v1: Returns 400, 404, 500
v1: Returns 400, 404, 422, 500 // Added 422, safe
β
Adding new values to enums
v1: status = "active" | "inactive"
v1: status = "active" | "inactive" | "suspended" // Safe if clients ignore unknown
β
Bug fixes that don't change contract
v1: Returns duplicate items in list
v1: Returns deduplicated list // Bug fix, safeThe Robustness Principle (Postel's Law)
"Be conservative in what you send, be liberal in what you accept."
Good API clients ignore unknown fields. This makes adding fields non-breaking. Teach your developers to write resilient clients!
When to Version (And When Not To)
When to Create a New Version
- β Breaking changes: Anything that breaks existing clients (see above)
- β Major data model changes: Switching from flat to nested objects
- β Authentication changes: OAuth 1 β OAuth 2, API keys β JWT
- β Response format changes: XML β JSON, single object β paginated list
- β Batch vs non-batch: GET /user/:id β GET /users (array)
When NOT to Version
- β Adding optional fields: Just add them (non-breaking)
- β Bug fixes: Fix in current version, backport to old versions if supported
- β Performance improvements: Transparent to clients
- β Adding new endpoints: New resources don't break existing ones
- β Security patches: Apply to all supported versions immediately
Version Fatigue: Don't Over-Version
β οΈ Anti-Pattern: Too Many Versions
β Bad: v1, v1.1, v1.2, v2, v2.1, v2.2, v3, v3.1 // Version fatigue!
β
Good: v1, v2, v3 // Major versions onlyToo many versions = maintenance nightmare. Aim for 2-3 active versions maximum.
The Stripe Rule
Stripe has a great policy: New features are added to the latest version only. Want the new feature? Upgrade. This incentivizes migration.
Deprecation & Sunset Strategies
Eventually, you need to retire old versions. Do it gracefully:
The 4-Phase Deprecation Process
Phase 1: Announcement (6-12 months before sunset)
- π’ Announce deprecation in release notes, blog, email
- π’ Add
SunsetHTTP header:Sunset: Sat, 01 Sep 2026 00:00:00 GMT - π’ Return
Deprecation: trueheader on deprecated endpoints - π’ Update API docs with big warning banner
Phase 2: Warning Period (3-6 months before sunset)
- β οΈ Add console warnings in SDK clients
- β οΈ Send emails to active API users
- β οΈ Track usage metrics (identify high-volume clients)
- β οΈ Reach out to top 20 clients personally
Phase 3: Rate Limiting (1-2 months before sunset)
- π¦ Gradually reduce rate limits on old version
- π¦ Return
X-Deprecation-Warningwith every response - π¦ Show migration guides in error messages
Phase 4: Sunset (D-Day)
- π΄ Return
410 Gonefor all requests - π΄ Response body includes migration guide link
- π΄ Monitor support tickets (offer emergency extensions if needed)
Sunset Response Example
HTTP/1.1 410 Gone
Content-Type: application/json
{
"error": "API_VERSION_SUNSET",
"message": "API v1 was sunset on September 1, 2026",
"migration_guide": "https://docs.example.com/migrate-v1-to-v2",
"support_email": "api-support@example.com"
}HTTP Headers for Deprecation
# RFC 8594: The Sunset HTTP Header
Sunset: Sat, 01 Sep 2026 00:00:00 GMT
# Custom deprecation warning
Deprecation: true
X-API-Warn: "v1 will be sunset on 2026-09-01. Migrate to v2: https://..."
# Link to migration guide
Link: <https://docs.example.com/migrate-v1-to-v2>; rel="deprecation"How Long to Support Old Versions?
| API Type | Support Duration | Example |
|---|---|---|
| Public API (external devs) | 12-24 months | Stripe, Twilio |
| Partner API (B2B integrations) | 18-36 months | Salesforce, AWS |
| Internal API (same company) | 3-6 months | Microservices |
| Mobile app API | 24+ months | Users can't force-update |
GraphQL Versioning (The No-Versioning Approach)
Protect your personal data as a developer
API developers are targets for credential phishing. Optery removes your personal information from 400+ data brokers β make yourself harder to target.
Scan Free with Optery βGraphQL takes a different approach: no versioning at all. Instead, it uses schema evolution.
How GraphQL Avoids Versioning
- β Additive changes only: Add new fields, never remove old ones
- β
Deprecation markers: Mark fields as
@deprecated - β Client-driven queries: Clients request only the fields they need
- β Gradual migration: Clients update field by field, not all at once
Example: Deprecating a Field
type User {
id: ID!
name: String! @deprecated(reason: "Use 'fullName' instead")
fullName: String! # New field
email: String!
}
# Old clients continue using "name"
query {
user(id: "123") {
name # Still works, returns data
}
}
# New clients use "fullName"
query {
user(id: "123") {
fullName # Better field name
}
}When GraphQL Versioning Makes Sense
Even GraphQL sometimes needs versions for:
- π― Breaking type changes: Changing
ID!toString! - π― Authentication overhaul: New auth mechanism
- π― Complete schema redesign: GraphQL v2 with new root types
Solution: GraphQL can use URI path versioning too:
POST https://api.example.com/graphql/v1
POST https://api.example.com/graphql/v2Real-World Examples
Stripe: Date-Based Versions
Stripe uses date-based versions with pinning:
curl https://api.stripe.com/v1/charges \
-u sk_test_... \
-H "Stripe-Version: 2026-03-01"
# Each account pins to a specific date version
# Upgrade by changing the pinned version in dashboardWhy date-based? Stripe makes small improvements continuously. Dates give clients fine-grained control without version number inflation.
GitHub: API Version in Header
GitHub uses custom headers with date versions:
curl https://api.github.com/users/octocat \
-H "X-GitHub-Api-Version: 2026-03-01"Twitter: URI Path Versioning
Twitter (now X) uses simple numeric versions in the path:
https://api.twitter.com/1.1/statuses/update.json # v1.1 (deprecated)
https://api.twitter.com/2/tweets # v2 (current)AWS: Service-Specific Versioning
AWS uses dates in the API action target:
POST / HTTP/1.1
Host: dynamodb.us-east-1.amazonaws.com
X-Amz-Target: DynamoDB_20120810.GetItem
# Date embedded in target header (2012-08-10)Twilio: Date-Based URI Path
Twilio uses dates in the URI (their first API release date):
https://api.twilio.com/2010-04-01/Accounts/{AccountSid}/MessagesMigration Strategies
How do you get clients to migrate from v1 to v2?
1. Dual Write Pattern
Write to both old and new schemas during transition:
// v1 client writes
POST /api/v1/users
{ "name": "Alice" }
// Server transforms and writes to both schemas
db.usersV1.insert({ name: "Alice" })
db.usersV2.insert({ full_name: "Alice", email: null }) // Transform
// Eventually drop v1 writes when all clients migrated2. Adapter Pattern
Build adapters that convert between v1 and v2:
// v1 endpoint (adapter)
app.get('/api/v1/users/:id', async (req, res) => {
const user = await getUserV2(req.params.id); // Fetch from v2
res.json(transformV2toV1(user)); // Transform back to v1 format
});
function transformV2toV1(userV2) {
return {
id: userV2.id,
name: userV2.full_name.split(' ')[0] // Convert back
};
}3. Feature Flags for Gradual Rollout
// Enable v2 for beta testers only
app.get('/api/v2/users', (req, res) => {
const user = await getUser(req.userId);
if (featureFlags.isEnabled('v2-api', user)) {
return res.json(formatV2(user)); // v2 format
} else {
return res.json(formatV1(user)); // v1 format (fallback)
}
});4. SDKs with Auto-Migration
Provide official SDKs that handle version differences:
// SDK handles version internally
const client = new ApiClient({ version: '2' });
// Client code stays the same
const user = await client.users.get('123');
// SDK automatically uses /api/v2/users under the hood5. Incentivize Migration
- π New features only in v2: Want webhooks? Upgrade to v2
- π Better performance in v2: v1 gets 100 req/min, v2 gets 1000 req/min
- π Credits/discounts: Migrate by Q2 2026, get 3 months free
- π Priority support: v2 users get faster support responses
Best Practices
β 1. Version from Day One
Start with /v1/ even if you think you won't need it. Retrofitting versioning is painful.
β 2. Document Breaking Changes Clearly
Maintain a CHANGELOG with explicit "BREAKING" labels. Developers need to know what will break.
β 3. Use HTTP Headers for Deprecation
Sunset: Sat, 01 Sep 2026 00:00:00 GMT
Deprecation: trueβ 4. Track Version Usage
Monitor which versions are still in use. Identify high-volume clients before deprecation.
β 5. Make Breaking Changes Obvious
Don't hide breaking changes in MINOR or PATCH releases. Bump MAJOR version.
β 6. Provide Migration Guides
Write detailed migration docs with code examples. Show before/after for every change.
β 7. Support 2-3 Versions Maximum
v1 (sunset soon), v2 (current), v3 (beta). More than 3 = maintenance nightmare.
β 8. Use Semantic Versioning for SDKs
API versions: /v1/. SDK versions: npm install api-client@2.3.1
β 9. Test Backward Compatibility
Run v1 integration tests against v2 adapters. Ensure no silent breakage.
β 10. Communicate Early and Often
Announce deprecations 6-12 months in advance. Send emails, blog posts, in-app warnings.
Common Mistakes to Avoid
β 1. No Versioning from the Start
Mistake: GET /api/users (no version)
Problem: Can't introduce breaking changes without breaking everyone
Fix: Always start with /v1/
β 2. Versioning Everything
Mistake: /v1.2.5/users (too granular)
Problem: Version fatigue, maintenance nightmare
Fix: Major versions only (/v1/, /v2/)
β 3. Breaking Changes Without Version Bump
Mistake: Removing fields in v1.1
Problem: Breaks clients who thought v1 was stable
Fix: Breaking change = new major version (v2)
β 4. Forcing Immediate Migration
Mistake: "v1 sunset in 30 days"
Problem: Enterprise clients can't move that fast
Fix: 6-12 month deprecation windows
β 5. Silent Sunset (No Warning)
Mistake: Shut down v1 without notice
Problem: Breaks production apps, angry developers
Fix: Multi-phase deprecation process
β 6. Inconsistent Versioning Across Endpoints
Mistake: /v1/users but /api/v2/orders
Problem: Confusing, hard to document
Fix: Pick one strategy, apply everywhere
β 7. No Migration Guide
Mistake: "v2 is out, figure it out yourself"
Problem: Developers won't migrate (too risky)
Fix: Detailed migration docs with examples
β 8. Supporting Too Many Versions
Mistake: Maintaining v1, v2, v3, v4, v5 simultaneously
Problem: Security patches need 5x work
Fix: Deprecate aggressively, support 2-3 max
API Versioning Checklist
Before Launching Your API
- βChoose a versioning strategy (URI path recommended)
- βStart with
/v1/even if you think you won't need it - βDocument what constitutes a breaking change
- βSet up version tracking in analytics
- βWrite a versioning policy for your team
Before Releasing v2
- βWrite comprehensive migration guide with examples
- βMaintain CHANGELOG with all breaking changes listed
- βSet up adapters/transformers between v1 and v2
- βTest backward compatibility (v1 tests pass against v2 adapters)
- βAnnounce v2 beta to power users for feedback
When Deprecating v1
- βAnnounce deprecation 6-12 months in advance
- βAdd
Sunsetheader to all v1 responses - βEmail all active v1 API users
- βIdentify top 20 API consumers and reach out personally
- βSet up deprecation warnings in SDK clients
- βGradually reduce rate limits 2 months before sunset
- βMonitor support tickets for migration blockers
- βReturn
410 Goneon sunset date with migration link
Ongoing Maintenance
- βTrack version usage in analytics dashboard
- βApply security patches to all supported versions
- βReview version support policy quarterly
- βKeep version docs up to date
- βLimit supported versions to 2-3 maximum
Conclusion
API versioning is a contract between you and your developers. Choose a simple, explicit strategy (URI path versioning for most APIs), commit to supporting versions for reasonable timeframes (12-24 months), and communicate changes early and often.
The best versioning strategy is the one you can maintain consistently. Start with /v1/, avoid breaking changes when possible, and when you must break things, give developers plenty of time to migrate.
Key Takeaways
- β
Use URI path versioning (
/v1/,/v2/) for simplicity - β
Expose major versions only (not
v1.2.3) - β Breaking changes = new version, non-breaking = same version
- β Support 2-3 versions maximum
- β Give 6-12 months for migration
- β
Use
SunsetandDeprecationheaders - β Provide detailed migration guides with code examples
Related Guides
API Rate Limiting Guide β
Implement production-ready rate limiting with token buckets, sliding windows, and Redis
Webhook Implementation Guide β
Build reliable event-driven APIs with security, retry logic, and idempotency
Circuit Breaker Pattern β
Prevent cascade failures and build resilient APIs that handle outages gracefully
Monitor API Status β
Check real-time status of Stripe, GitHub, AWS, and 400+ other APIs
Monitor your APIs and infrastructure in real-time
Better Stack combines uptime monitoring, incident management, and log aggregation. Free tier includes 10 monitors with 3-minute checks.
Try Better Stack Free βπ Tools We Use & Recommend
Tested across our own infrastructure monitoring 200+ APIs daily
Uptime Monitoring & Incident Management
Used by 100,000+ websites
Monitors your APIs every 30 seconds. Instant alerts via Slack, email, SMS, and phone calls when something goes down.
βWe use Better Stack to monitor every API on this site. It caught 23 outages last month before users reported them.β
Secrets Management & Developer Security
Trusted by 150,000+ businesses
Manage API keys, database passwords, and service tokens with CLI integration and automatic rotation.
βAfter covering dozens of outages caused by leaked credentials, we recommend every team use a secrets manager.β
SEO & Site Performance Monitoring
Used by 10M+ marketers
Track your site health, uptime, search rankings, and competitor movements from one dashboard.
βWe use SEMrush to track how our API status pages rank and catch site health issues early.β