---
title: "API Consumer Migration Guide"
description: "Update your API endpoint URLs and switch to OAuth 2.0 authentication. Step-by-step guide with code examples for the Schiphol API platform."
url: "https://developer.schiphol.nl/news-and-updates/api-consumer-migration-guide"
image: "https://developer.schiphol.nl/_og/d/c_Ocean.takumi,title_API+Consumer+Migration+Guide,description_Update+your+API+endpoint+URLs+and+switch+to+OAuth+2.0+authentication.+Step-by-step+guide+with+code+examples+for+the+Schiphol+API+platform.,props_eyJ0aGVtZSI6eyJtb2RlIjoibGlnaHQiLCJjb2xvcnMiOnt9fX0,p_Ii9uZXdzLWFuZC11cGRhdGVzL2FwaS1jb25zdW1lci1taWdyYXRpb24tZ3VpZGUi,s_TMa9EQ_PrVAajQrI.png"
---

[← Back to News & Updates](https://developer.schiphol.nl/news-and-updates)

Migration

July 20, 2026

API Consumer Migration Guide

By Schiphol API Team

![Migration Guide](https://images.ctfassets.net/9bvisqn57bx6/66cLQJMOS3ZFxzih18FrTn/1759315b8a111b908fb0192905b46466/team_working_on_digital_security_diagrams.svg)

What's Changing

Two changes required to update your integration

1

Update Your API Endpoint URLs

Your API base URLs now include a tier prefix - **/public**, **/partner**, or **/internal** that must be added to every API call.

URL Change Required

2

Switch to OAuth 2.0 Authentication

Replace App\_Id / App\_Key headers with OAuth 2.0 Client Credentials. Obtain a short-lived JWT token from Auth0 and include it as a Bearer token on every API call.

Auth Change Required

This guide is for teams who need to update their integration with the Schiphol API platform. Two changes are required: update your endpoint URLs and switch to OAuth 2.0 authentication.

## [1\. Endpoint Changes](#_1-endpoint-changes)

Every API endpoint is now prefixed with its tier type: `/public`, `/partner`, or `/internal`. Update all your API call URLs to include this prefix.

| API Type | Before Previous Endpoint               | New Updated Endpoint                          |
| :------- | :------------------------------------- | :-------------------------------------------- |
| Public   | api.schiphol.nl/public-flights/flights | api.schiphol.nl/public/public-flights/flights |

### [API Version: Now in the URL Path](#api-version-now-in-the-url-path)

ResourceVersion header deprecated

The `ResourceVersion` request header is no longer supported. Specify the API version directly in the URL path instead.

Previously you could select the API resource version by passing a `ResourceVersion` header on each request. This header is now deprecated and will be ignored. The version must be included as a fixed segment in the URL path.

| Before Header-based versioning             | New URL path versioning    |
| :----------------------------------------- | :------------------------- |
| /public-flights/flightsResourceVersion: v4 | /public-flights/v4/flights |

The current version is **v4**. Always include the version segment when constructing your request URLs.

## [2\. Authentication: OAuth 2.0 Client Credentials](#_2-authentication-oauth-20-client-credentials)

The previous authentication method used static API key headers sent with every request. The Schiphol API platform uses the industry-standard **OAuth 2.0 Client Credentials Flow**, designed for machine-to-machine communication with short-lived, secure tokens.

What changes?

Instead of sending App\_Id and App\_Key on every call, you exchange your Client ID & Secret for a JWT token once, then include that token as a Bearer header on every API call. Tokens expire after 30 minutes and must be refreshed.

### [Authentication Flow Overview](#authentication-flow-overview)

1

Get Client ID & Secret from the Developer Portal

Create an application on the portal for your API tier. Your credentials are shown once - store the Client Secret immediately in a secrets manager.

2

Request a JWT token from Auth0

POST your Client ID, Secret, and API audience to the token endpoint. You receive a JWT valid for 30 minutes. Cache it and reuse it for all subsequent calls.

3

Include the token in every API call

Add the JWT to the `Authorization: Bearer <token>` header. Multiple requests share one token until expiry. Refresh proactively - 60 seconds before the token expires.

### [Step 1 - Get your credentials](#step-1-get-your-credentials)

1.  Go to the Developer Portal for your API tier (see sidebar for links)
2.  Log in or sign up (public portal requires registration)
3.  Navigate to **Applications** and create a new application
4.  Copy your **Client ID** and **Client Secret** - the Secret is shown only once
5.  Subscribe to the APIs you need and await approval if required

Security Notice

Your Client Secret is shown only once. Store it immediately in a secrets manager (e.g. Azure Key Vault). Never commit secrets to source control or expose them in client-side code.

### [Step 2 - Request a JWT token](#step-2-request-a-jwt-token)

Send a `POST` request to the Auth0 token endpoint for your target environment:

| Environment | Token Endpoint                           |
| :---------- | :--------------------------------------- |
| PRD         | https://api.auth.schiphol.nl/oauth/token |

| Parameter     | Required | Description                                           |
| :------------ | :------- | :---------------------------------------------------- |
| grant_type    | Yes      | Must be client_credentials                            |
| client_id     | Yes      | Your application's Client ID                          |
| client_secret | Yes      | Your application's Client Secret                      |
| audience      | Yes      | API audience URL, e.g. https://api.schiphol.nl/public |

curl -X POST "https://api.auth.schiphol.nl/oauth/token" \\
 -H "Content-Type: application/x-www-form-urlencoded" \\
 -d "grant\_type=client\_credentials" \\
 -d "client\_id=YOUR\_CLIENT\_ID" \\
 -d "client\_secret=YOUR\_CLIENT\_SECRET" \\
 -d "audience=https://api.schiphol.nl/public"

What is the audience?

The `audience` identifies which API you are requesting a token for. It must exactly match the **tier** and **environment** of the API you intend to call, otherwise the token is rejected with a `401` or `403`. For the **public** tier use `https://api.schiphol.nl/public`. Each token is scoped to a single audience, so request a separate token per tier.

Expected response:

{
 "access\_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
 "token\_type": "Bearer",
 "expires\_in": 1800
}

### [Step 3 - Call the API with your token](#step-3-call-the-api-with-your-token)

Add the `access_token` as a Bearer token in the `Authorization` header on every API call.

curl -X GET "https://api.schiphol.nl/public/public-flights/v4/flights" \\
 -H "Authorization: Bearer YOUR\_ACCESS\_TOKEN" \\
 -H "Accept: application/json"

### [Code Examples](#code-examples)

Choose your language below for a complete, production-ready implementation with automatic token caching and refresh.

cURL: Quick Testing +

**Step 1:** Fetch and store the access token

TOKEN=$(curl -s -X POST https://api.auth.schiphol.nl/oauth/token \\
 -H "Content-Type: application/x-www-form-urlencoded" \\
 -d "grant\_type=client\_credentials" \\
 -d "client\_id=${SCHIPHOL\_CLIENT\_ID}" \\
 -d "client\_secret=${SCHIPHOL\_CLIENT\_SECRET}" \\
 -d "audience=https://api.schiphol.nl/public" \\
 | jq -r '.access\_token')

**Step 2:** Call the API using the stored token

curl -X GET "https://api.schiphol.nl/public/public-flights/v4/flights" \\
 -H "Authorization: Bearer ${TOKEN}" \\
 -H "Accept: application/json"
Python: With Automatic Token Refresh +

```
def __init__(self, client_id: str, client_secret: str):
    self.client_id = client_id
    self.client_secret = client_secret
    self._token = None
    self._expires_at = None
    self._lock = threading.Lock()

def _get_token(self) -> str:
    with self._lock:
        buffer = timedelta(seconds=60)
        if not self._token or datetime.utcnow() >= self._expires_at - buffer:
            r = requests.post(self.TOKEN_URL, data={
                "grant_type": "client_credentials",
                "client_id": self.client_id,
                "client_secret": self.client_secret,
                "audience": self.AUDIENCE,
            })
            r.raise_for_status()
            data = r.json()
            self._token = data["access_token"]
            self._expires_at = datetime.utcnow() + timedelta(seconds=data["expires_in"])
    return self._token

def get(self, path: str, **kwargs) -> requests.Response:
    headers = kwargs.pop("headers", {})
    headers["Authorization"] = f"Bearer {self._get_token()}"
    return requests.get(f"{self.BASE_URL}{path}", headers=headers, **kwargs)
```
Java: Spring WebClient (OAuth2) +

\# application.yml
spring:
  security:
    oauth2:
      client:
        registration:
          schiphol:
            client-id: ${SCHIPHOL\_CLIENT\_ID}
            client-secret: ${SCHIPHOL\_CLIENT\_SECRET}
            authorization-grant-type: client\_credentials
            provider: schiphol
        provider:
          schiphol:
            token-uri: https://api.auth.schiphol.nl/oauth/token

```
@Bean
public WebClient schipholApiClient(
        ReactiveClientRegistrationRepository registrations,
        ServerOAuth2AuthorizedClientRepository clients) {

    var oauth = new ServerOAuth2AuthorizedClientExchangeFilterFunction(registrations, clients);
    oauth.setDefaultClientRegistrationId("schiphol");

    return WebClient.builder()
            .baseUrl("https://api.schiphol.nl/public")
            .filter(oauth)
            .build();
}
```
Node.js: With Automatic Token Refresh +

```
${this.baseUrl}${path}
```

## [3\. Best Practices](#_3-best-practices)

Token Management +

Do

-   Cache tokens and reuse until near expiry
-   Refresh proactively, 60 s before expiry
-   Use thread-safe token storage in concurrent apps
-   Implement exponential backoff on token failures

Don't

-   Request a new token for every API call
-   Wait for a 401 error before refreshing
-   Share token state without synchronisation
-   Ignore the `expires_in` response field

Secret Management +

Do

-   Store secrets in environment variables or a vault
-   Use Azure Key Vault, HashiCorp Vault, or similar
-   Rotate secrets regularly
-   Use separate credentials per environment

Don't

-   Hardcode secrets in source code
-   Commit secrets to version control
-   Share credentials across environments
-   Log or print secrets in error messages

## [4\. Troubleshooting](#_4-troubleshooting)

HTTP 401  Unauthorized +

| Cause                        | Solution                                                                         |
| :--------------------------- | :------------------------------------------------------------------------------- |
| Token expired                | Check your refresh logic - read expires_in and refresh 60 s before expiry.       |
| Invalid credentials          | Verify Client ID and Secret in the Developer Portal or create a new application. |
| Missing Authorization header | Ensure every request includes Authorization: Bearer <token>.                     |
| Wrong audience               | The audience in your token request must match the API tier URL you are calling.  |

HTTP 403  Forbidden +

| Cause                         | Solution                                                                         |
| :---------------------------- | :------------------------------------------------------------------------------- |
| API not subscribed            | Subscribe to the API in the Developer Portal. Only approved subscriptions grant access. |
| Subscription pending approval | Some APIs require manual approval. Check your application status in the portal.  |
| Insufficient scope            | Your application may need additional permissions - contact the API team.         |

HTTP 429  Too Many Requests +

You have exceeded a rate limit. Implement exponential backoff and ensure you are caching tokens rather than requesting a new one on every call.

| Endpoint               | Limit                                        |
| :--------------------- | :------------------------------------------- |
| Token endpoint (Auth0) | See Auth0 rate limit policy                  |
| API endpoints          | Varies by API - see each API's documentation |

Token Request Errors +

| Error               | Cause                                     | Solution                                              |
| :------------------ | :---------------------------------------- | :---------------------------------------------------- |
| invalid_client      | Wrong Client ID or Secret                 | Double-check credentials in the Developer Portal      |
| invalid_grant       | Incorrect grant type                      | Use grant_type=client_credentials                     |
| rate_limit_exceeded | Too many token requests                   | Cache and reuse tokens; refresh only when near expiry |
| unauthorized_client | Client not authorised for this grant type | Verify your application settings in the portal        |

## [Need Help?](#need-help)

Check the [API catalogue](https://developer.schiphol.nl/apis) for endpoint details, or contact the Schiphol API team for support. You can also visit the [Getting Started Guide](https://developer.schiphol.nl/news-and-updates/api-consumer-getting-started-guide) for a step-by-step introduction to the platform.

Migration Checklist

-   1
    
    Update all endpoint URLs with the tier prefix
    
-   2
    
    Log in to the Developer Portal for your API tier
    
-   3
    
    Create an application and save Client ID & Secret securely
    
-   4
    
    Subscribe to required APIs and await approval
    
-   5
    
    Implement token request and Bearer token logic
    

Developer Portals

-   Public [developer.schiphol.nl](https://developer.schiphol.nl/)

Auth0 Token Endpoints

-   PRD api.auth.schiphol.nl/oauth/token

### [Flights](#flights)

-   [Departures](https://www.schiphol.nl/en/departures/)
-   [Arrivals](https://www.schiphol.nl/en/arrivals/)
-   [Transfers](https://www.schiphol.nl/en/transfers/)

### [Things to do at Schiphol](#things-to-do-at-schiphol)

-   [Shop](https://www.schiphol.nl/en/at-schiphol/shop/)
-   [Eat and drink](https://www.schiphol.nl/en/at-schiphol/eat-and-drink/)
-   [Airport maps](https://www.schiphol.nl/en/airport-maps/)
-   [Services](https://www.schiphol.nl/en/services/)

### [Check-in](#check-in)

-   [Ways to check in](https://www.schiphol.nl/en/check-in/)
-   [Baggage rules and checks](https://www.schiphol.nl/en/baggage/)
-   [How busy is Schiphol](https://www.schiphol.nl/en/busy/)

### [Traveling to and from Schiphol](#traveling-to-and-from-schiphol)

-   [All parking options](https://www.schiphol.nl/en/parking/)
-   [All travel options](https://www.schiphol.nl/en/from-to-schiphol/)
-   [Short-term parking](https://www.schiphol.nl/en/parking/short-term/)
-   [Long term parking](https://www.schiphol.nl/en/parking/long-term/)
-   [Pick-up & drop-off](https://www.schiphol.nl/en/pick-up-and-drop-off/)

### [All Schiphol websites](#all-schiphol-websites)

-   [Royal Schiphol Group](https://www.royalschipholgroup.com/)
-   [Sustainability](https://www.schiphol.nl/en/sustainability/)
-   [Operations](https://www.schiphol.nl/en/operations/)
-   [Schiphol as a neighbour](https://www.schiphol.nl/en/schiphol-as-a-neighbour/)
-   [Careers at Schiphol Group](https://werkenbijschiphol.nl/)
-   [You and Schiphol](https://www.schiphol.nl/en/you-and-schiphol/)
-   [Developer Center](https://developer.schiphol.nl/)

![Developer Portal](https://developer.schiphol.nl/_core/api/v3/assets/logo?ref=1763460379699) © Schiphol 2025

-   [Privacy](https://www.schiphol.nl/en/privacy/)
-   [Schiphol regulations](https://www.schiphol.nl/en/regulations/)
-   [Accessibility](https://www.schiphol.nl/en/accessibility/)
-   [Disclaimer](https://www.schiphol.nl/en/disclaimer/)
-   [Newsletter](https://www.schiphol.nl/en/newsletter/)
-   [Contact us](https://www.schiphol.nl/en/contact/)