Understand per-tier limits, monitor quota headers, and implement exponential backoff with jitter.
PerformanceCache tokens, refresh proactively 60 s before expiry, and use thread-safe storage in concurrent apps.
ReliabilityMatch cache TTL to data freshness - from 24 h for static data to 15 s for real-time status.
PerformanceHandle every HTTP status code and design with circuit breakers and graceful fallbacks.
ReliabilityStore secrets in a vault, use per-environment credentials, and rotate regularly.
SecurityValidate your integration end-to-end: token flow, error handling, retries, and timeouts before going to production.
QualityBuilding robust integrations with Schiphol APIs requires following patterns that ensure reliability, performance, and a smooth experience for your users. This guide covers the essential practices every developer should apply - whether you are building a new integration from scratch or hardening an existing one.
1. Rate Limiting
All Schiphol APIs enforce rate limits per application to ensure fair usage and platform stability. Exceeding a limit returns a 429 Too Many Requests response with a Retry-After header indicating how long to wait.
| Tier | Rate Limit | Notes |
|---|---|---|
| Public | 100 requests / minute | Suitable for display and informational applications |
2. Token Management
OAuth 2.0 access tokens are valid for 30 minutes. Mismanaging tokens is the most common cause of 401 Unauthorized errors in production.
Never request a new token for every API call. A single token is valid for 30 minutes and should serve all requests within that window. Requesting a new token per call wastes Auth0 quota and adds 100-200 ms latency to every request.
Read expires_in from the token response (usually 1800 s = 30 min). Schedule a background refresh 60 s before the token expires. This ensures you always have a valid token ready and avoids in-flight requests receiving a 401.
In multi-threaded or async apps, protect token state with a mutex or lock. Without synchronisation, multiple threads may all detect token expiry simultaneously and each request a new token - this is the "token stampede" problem and will hit Auth0 rate limits.
Never hardcode Client ID or Client Secret in source code or config files. Use Azure Key Vault, HashiCorp Vault, or environment variables. Rotate secrets at least every 90 days and immediately if a secret is exposed.
In high-concurrency systems, if the token expires and 50+ threads all detect it simultaneously, they may all try to refresh at once. Use a single background token-refresh worker and share the token reference with all threads via a read-write lock.
3. Caching Strategies
Caching is the single most effective way to reduce API call volume, lower latency, and stay within rate limits. Different data types have different freshness requirements - match your TTL to the data, not to a single global setting.
| Data Type | Recommended TTL | Notes |
|---|---|---|
| Static reference data - airlines, destinations, aircraft types | 24 hours | Changes very rarely; safe to cache aggressively |
| Flight schedules | 5-15 minutes | Changes a few times per day; short TTL is sufficient |
| Flight status - gate, delay, boarding | 30-60 seconds | Time-sensitive; keep cache short |
| Real-time arrivals / departures | 15-30 seconds | Even a 15 s cache dramatically cuts repeated identical calls |
| User-specific / subscription data | Do not cache | Never share personalised data across callers |
Application-level vs. per-user caches
Flight schedule and status data is the same for all users - cache it at the application level and serve all users from a single cache entry. Never cache data that contains user-specific subscription or authorisation information in a shared cache.
Stale-while-revalidate pattern
For non-critical data, serve the stale cached version immediately while refreshing in the background. This eliminates cache-miss latency spikes at TTL boundaries. Suitable for flight schedules and reference data - do not use for real-time status data where freshness is critical.
4. Error Handling
Robust error handling ensures your application degrades gracefully rather than failing hard when the API returns an unexpected response. Design every integration to handle failure as a first-class concern.
| Status | Meaning | Recommended Action |
|---|---|---|
200-299 | Success | Process the response normally |
304 | Not Modified | Use your cached copy - nothing has changed |
400 | Bad Request | Fix the request (invalid parameter, missing field) - do not retry as-is |
401 | Unauthorized | Refresh the access token and retry the request once |
403 | Forbidden | Check subscription status - approval may be pending; contact the API team |
404 | Not Found | Validate the flight number, ID, or resource path |
429 | Too Many Requests | Back off exponentially; always honour the Retry-After header |
500 | Server Error | Retry with exponential backoff - do not try to fix in the client |
503 | Service Unavailable | The service is temporarily down; retry after the Retry-After period |
Treat every external API call as potentially failing. Use timeouts (5 s connect / 10 s read), circuit breakers to stop calling a failing API, and fallback values so a temporary API issue does not cascade into a full application outage.
Which errors are safe to retry?
Safe to retry (with backoff): 429, 500, 502, 503, 504, and network timeouts.
Do not retry: 400 (fix your request first), 401 (refresh token then retry once), 403 (subscription issue - retrying won't help), 404 (resource does not exist).
5. API Versioning
Always pin your integration to a specific API version. Calling an unversioned endpoint may result in silent breaking changes when we release a new major version.
- Specify the version in the URL path:
/public-flights/v4/flights - Subscribe to the News & Updates page for version announcements and deprecation notices
- Allow at least 2 weeks of parallel testing before switching your production integration
We support each major API version for at least 18 months after the next version is released. Deprecation notices are published at least 6 months before end-of-life. You will never wake up to a surprise breaking change.
6. Security
Credential exposure is the most common security incident in API integrations. Follow these rules without exception.
- Store Client ID & Secret in a secrets manager (Azure Key Vault, HashiCorp Vault)
- Use separate credentials per environment (dev, test, production)
- Rotate secrets at least every 90 days
- Revoke and reissue immediately if a secret is exposed
- Validate and sanitise all API response data before using it
- Hardcode secrets in source code or config files
- Commit secrets to version control - even private repos
- Expose the Client Secret in client-side JavaScript or mobile apps
- Share one credential set across multiple teams or environments
- Log access tokens or secrets in application logs or error messages
7. Performance Tips
Small optimisations compound. Use the following patterns to get the most performance out of every API call.
Use pagination and field filtering
Most list endpoints support page and pageSize parameters. Always paginate large result sets - fetching everything in one call is wasteful and slow. Where the API supports field selection, request only the fields your application uses. Smaller payloads are faster and cheaper on bandwidth.
GET /public/public-flights/v4/flights?page=0&pageSize=20
Set connection and read timeouts
Always configure explicit timeouts on your HTTP client. Without them, a slow or hung response will block a thread indefinitely and exhaust your thread pool.
Recommended: 5 s connection timeout · 10 s read timeout. If your use case requires longer timeouts (e.g. large schedule downloads), set them explicitly and log slow responses for monitoring.
Reuse HTTP connections (Keep-Alive / connection pooling)
Establishing a new TLS connection for every request adds 100-300 ms of overhead. Use an HTTP client that supports keep-alive and connection pooling. Most popular libraries handle this automatically when you reuse the client instance:
- Python: use a
requests.Session()object - Java: use
WebClientor a sharedOkHttpClient - Node.js:
axiosandnode-fetchreuse connections by default
8. Testing & Environments
Validate your integration end-to-end before going live. Test token acquisition, error handling, retries, and edge cases with low-volume calls against the production environment.
What to test before going to production
Run the following checklist before going live:
- Token acquisition and automatic refresh works correctly
- All expected HTTP status codes (200, 401, 403, 429, 500) are handled
- Exponential backoff fires correctly on 429 and 5xx responses
- Responses are parsed correctly for edge cases (empty arrays, null fields)
- Timeouts are configured and do not hang the application
- Caching returns fresh data and does not serve stale responses indefinitely
- No secrets or tokens appear in application logs