Skip to main content

Versioning

The J.P. Morgan Payments Platform APIs will undergo changes over time due to various factors, including strategic business shifts and advancements in our software platforms.

To maintain a consistent and reliable client experience, J.P. Morgan is committed to:

  • Implementing a well-defined API versioning strategy.
  • Offering clear and concise documentation and client communications.
  • Ensuring full transparency when functionalities are scheduled for deprecation or retirement.

Versioning strategy

The versioning strategy for the J.P. Morgan Payments Platform is designed to enable the evolution of our APIs without disrupting client integrations, as long as the guidelines outlined are followed. 

Versioning scheme for APIs

The versioning system employed for the J.P. Morgan Payments Platform APIs adheres to the Semantic Versioning approach, which distinguishes between breaking and non-breaking changes. The following diagram illustrates an example of a typical numbering scheme.

Common Numbering Scheme Example

Major, minor, and patch versions

  • Major version: The first number increases when a change is made that is not backward-compatible. For instance, updating from version 1.2.4 to a new major version would result in version 2.0.0.
  • Minor version: The second number increases with backward-compatible changes, such as adding new operations to an existing API. For example, a minor update from version 1.2.4 would lead to version 1.3.0.
  • Patch version: The third number increases for backward-compatible bug fixes, such as updates to clarify documentation in an API contract. For example, a patch update from version 1.2.4 would result in version 1.2.5.

API release states

Once released, a J.P. Morgan Payments Platform API can be in one of three states: active, deprecated, or retired. The following diagram illustrates an example of these release states for different API versions over time.

Release States Example
  • Active: In the active state, the API is ready for production use and is fully supported, with new features and bug fixes included in future releases. Comprehensive API documentation is available on the developer portal. Multiple API versions can be active simultaneously.
  • Deprecated: In the deprecated state, the process of retiring a specific API version has begun. This may occur due to the release of a new major version or an upcoming reduction in service. Functionality is typically maintained for 18-months from the deprecation notice until permanent retirement. The API remains operational and fully supported, but new integrations are strongly discouraged and may be restricted by J.P. Morgan in certain cases. During the deprecation period, no new features will be added to the API. It is advisable to update existing applications to the active version to avoid future service interruptions.
  • Retired: In the retired state, an API version is no longer available, supported, or documented.

Communication

As the J.P. Morgan Payments Platform APIs evolves, J.P. Morgan will make reasonable efforts to notify you in advance of the breaking changes, providing sufficient time to adapt. Updates will include:

  • Posting changes to the changelog on the Payments Developer Portal.
  • Sending email notifications to client contacts.
Tip

J.P. Morgan may implement non-breaking changes without prior notice. Additionally, breaking changes may be made without prior notice if necessary to address critical product bugs or legal, security, or privacy concerns.

Client impact of migrating to higher versions

Upgrading to a higher patch version

If you're a J.P. Morgan client using API version 1.2.4, your API client application will automatically transition to version 1.2.5 once it is released. This upgrade includes a bug fix and should not require any changes to your existing code, apart from updating version number references where applicable.

Upgrading to a higher minor version

For client applications using API version 1.2.5, if you wish to access a new feature introduced in version 1.3.0, your application will automatically transition to version 1.3.0 once it is released. You can upgrade your client application with the new code changes to leverage the new feature.

Upgrading to a higher major version

If your client applications are designed for API version 1.3.0 and you plan to migrate to version 2.0.0, you must account for breaking changes introduced in the major release. This upgrade will require development and thorough testing of your client application, along with code changes to ensure compatibility with version 2.0.0.

When to migrate your code to a newer API version

When planning to migrate your code to the latest API version, consider the following factors:

  • Deprecation and retirement schedule: Avoid using a deprecated API if possible, as it may not receive bug fixes and you won't have access to the latest features. A retired API may cease to function entirely. Since the typical timeline for a J.P. Morgan Payments API from deprecation to retirement is approximately 18-months, plan your code migration accordingly.
  • Availability of new features: By using the latest API version, you ensure access to the newest features. Migrating your code to the latest API can be a proactive strategy to stay up-to-date.

Types of API changes and versioning effects

API updates can be categorized as either non-breaking or breaking changes, the latter disrupting compatibility for the API client.

Non-breaking changes

These changes typically do not disrupt the functionality of your existing applications using the API. They include minor bug fixes or feature updates, and your application should be resilient to such changes. Examples of non-breaking changes include: 

  • Adding new API endpoints, optional fields, query parameters, or HTTP headers.
  • Introducing new fields or headers in responses.
  • Adding new enum values in requests.
  • Making required fields, parameters, or headers optional.
  • Expanding the range of allowed values.
  • Changing the order of fields in responses.
  • Implementing bug fixes on existing APIs.
  • Deprecating existing optional elements.

J.P. Morgan will manage non-breaking changes without creating a new URL-level version. Instead, the version number will be updated as described in Versioning scheme for APIs section.

Breaking changes

These changes, often driven by business or technical enhancements, can impact existing applications when a new major API version is introduced. Assessing these changes before adoption is crucial. Examples of breaking changes include:

  • Removing a mandatory request or response field.
  • Adding a required or optional request field without default values.
  • Altering the intended functionality of an endpoint.
  • Implementing new field validation.
  • Changing the data type of an existing field.
  • Removing or renaming an endpoint's URL.
  • Adding a required header to an existing endpoint.
  • Modifying existing error codes or messages.
  • Introducing new features such as payload signing and additional encryption.
  • Altering the existing payload of webhooks or asynchronous callbacks.
  • Retiring an API.

Integration expectations for non-breaking changes

In JSON-based REST APIs, additive changes are generally non-breaking. J.P. Morgan introduces new API features and updates while maintaining backward compatibility.

As a result, client integrations should be able to handle additional JSON properties in the request or response payloads. Your code must remain functional when a non-breaking change is made to an OpenAPI specification. However, if issues arise, they may be due to the following reasons:

  • Insufficient error handling: Your code should already include mechanisms to handle unexpected or unknown fields gracefully.
  • Overly specific or rigid code: Your code may be too specific or rigid, expecting an exact response order or structure. 

Examples of non-resilient code

The following scenarios illustrate how API clients can become tightly coupled to a REST API schema. These practices should be avoided to ensure integration remains resilient to non-breaking changes.

Strict mode parsing

For instance, using strict mode parsing in Java can lead to exceptions if the object (POJO) does not precisely match the incoming JSON response.

Code management with API changes
Java
new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, true);

An API client application becomes less resilient when it relies on hard-coded field names and paths, especially for optional and non-guaranteed fields. If the API schema changes, such as a field being removed, renamed, or made optional, the client code may break or produce unexpected results.

The following C++ code for a .NET platform illustrates the user.email field, which may not always be present in the response schema. This issue also applies to the Java code block that follows, which assumes a fixed schema structure without validation or fallback handling.

Hard-coded field names and paths
Plaintext
using System;
using System.Net.Http;
using System.Threading.Tasks;
using Newtonsoft.Json.Linq;
public class CotsClient
{
    private static readonly HttpClient client = new HttpClient();
    public async Task GetUserData()
    {
        HttpResponseMessage response = await client.GetAsync("https://api.example.com/users/1");
        response.EnsureSuccessStatusCode();
        string responseBody = await response.Content.ReadAsStringAsync();
        JObject user = JObject.Parse(responseBody);
        Console.WriteLine("ID: " + user["id"]);
        Console.WriteLine("Name: " + user["name"]);
        Console.WriteLine("Email: " + user["email"]); // Tightly coupled to the "email" field
    }
}

Strictly typed data models

The API client application might use strictly typed data models that expect a specific JSON structure, making it difficult to handle changes in the API schema, as shown in the following example of Java code.

Strictly typed data models
Java
import com.fasterxml.jackson.databind.ObjectMapper;
public class CotsClient {
    private static final ObjectMapper objectMapper = new ObjectMapper();
    public static void main(String[] args) throws Exception {
        String jsonResponse = "{ \"id\": 1, \"name\": \"John Doe\", \"email\": \"john.doe@example.com\" }";
        User user = objectMapper.readValue(jsonResponse, User.class);
        System.out.println("ID: " + user.getId());
        System.out.println("Name: " + user.getName());
        System.out.println("Email: " + user.getEmail()); // Tightly coupled to the "email" field
    }
    public static class User {
        private int id;
        private String name;
        private String email; // Tightly coupled to the "email" field
        public int getId() {
            return id;
        }
        public String getName() {
            return name;
        }
          public String getEmail() {
            return email;
        }
    }
}

Inadequate error handling for missing or additional fields

An API client application may fail to manage missing or additional fields effectively, resulting in errors when the API schema is modified. This issue is illustrated in the following example of Python code.

Inadequate error handling for missing or additional fields
Python
import json 
def get_user_data(): 
    json_response = '{"id": 1, "name": "John Doe"}'  # "email" field is missing 
    user = json.loads(json_response) 
    try: 
        print("ID:", user["id"]) 
        print("Name:", user["name"]) 
        print("Email:", user["email"])  # Tightly coupled to the "email" field 
    except KeyError as e: 
        print(f"Missing field: {e}") 
get_user_data() 

Rigid validation rules

An API client application may enforce strict validation rules that require a specific JSON structure, making it challenging to accommodate changes in the API schema. This is demonstrated in the following example of JavaScript code.

Rigid validation rules
Javascript
function validateUserData(user) {
    if (!user.id || !user.name || !user.email) {  // Tightly coupled to the "email" field
        throw new Error("Invalid user data");
    }
}
const jsonResponse = '{"id": 1, "name": "John Doe"}';  // "email" field is missing
const user = JSON.parse(jsonResponse);
try {
    validateUserData(user);
    console.log("User data is valid");
} catch (error) {
    console.error(error.message);
}

Writing resilient code for API consumption

As an API consumer, it's crucial to develop code that can adapt to changes in the JSON schema of the API. To achieve this, avoid tightly coupling your code to the precise structure of JSON responses. The following strategies and Java examples help you accomplish this:

Optional fields

Utilize Java's "Optional" class to manage fields that may or may not be present in the JSON response, as demonstrated in the following Java code example.

Use optional fields
Java
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.IOException;
import java.util.Optional;
public class ApiClient {
    private static final ObjectMapper objectMapper = new ObjectMapper();
    public static void main(String[] args) throws IOException {
        String jsonResponse = "{ \"id\": 1, \"name\": \"John Doe\" }";
        User user = objectMapper.readValue(jsonResponse, User.class);
        System.out.println("ID: " + user.getId());
        System.out.println("Name: " + user.getName());
        user.getEmail().ifPresent(email -> System.out.println("Email: " + email));
    }
    @JsonInclude(JsonInclude.Include.NON_NULL)
    public static class User {
        private int id;
        private String name;
        private String email;
        public int getId() {
            return id;
        }
        public String getName() {
            return name;
        }
        public Optional<String> getEmail() {
            return Optional.ofNullable(email);
        }
    }
}

Default values

Here's an example in Java demonstrating how to assign default values to fields that might be absent in a JSON response:

Use default values
Java
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.IOException;
public class ApiClient {
    private static final ObjectMapper objectMapper = new ObjectMapper();
    public static void main(String[] args) throws IOException {
        String jsonResponse = "{ \"id\": 1, \"name\": \"John Doe\" }";
        User user = objectMapper.readValue(jsonResponse, User.class);
        System.out.println("ID: " + user.getId());
        System.out.println("Name: " + user.getName());
        System.out.println("Email: " + user.getEmail());
    }
    @JsonInclude(JsonInclude.Include.NON_NULL)
    public static class User {
        private int id;
        private String name;
        private String email;
        public int getId() {
            return id;
        }
        public String getName() {
            return name;
        }
        public String getEmail() {
            return email != null ? email : "default@example.com";
        }
    }
}

Robust de-serialization

Utilize robust de-serialization techniques by employing suitable JSON deserializer libraries to gracefully manage unknown properties, as illustrated in the following Java code example:

Use robust de-serialization
Java
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.IOException;
public class ApiClient {
    private static final ObjectMapper objectMapper = new ObjectMapper();
    public static void main(String[] args) throws IOException {
        String jsonResponse = "{ \"id\": 1, \"name\": \"John Doe\", \"unknownField\": \"some value\" }";
        User user = objectMapper.readValue(jsonResponse, User.class);
        System.out.println("ID: " + user.getId());
        System.out.println("Name: " + user.getName());
    }
    @JsonIgnoreProperties(ignoreUnknown = true)
    public static class User {
        private int id;
        private String name;
        public int getId() {
            return id;
        }
        public String getName() {
            return name;
        }
    }
}

By implementing these strategies, you can enhance the resilience of your API client code to changes in the JSON schema, minimizing the risk of breaking changes and simplifying maintenance. J.P. Morgan advises adopting a comprehensive testing strategy during implementation to prevent code breakage. Ensure your application is supported by a robust suite of tests. Regularly run these tests to identify and address potential issues whenever a new API update is introduced.

J.P. Morgan's approach to managing breaking changes

As outlined in the Versioning Scheme for APIs section, J.P. Morgan will release a new version of the API when breaking changes occur. The updated OpenAPI specification will be made available on the Payments Developer Portal. The previous API version will remain supported for existing clients until they transition to the new APIs. New clients may not have access to the old API version, which will be marked as "deprecated" on the Payments Developer Portal. The version number will be updated in accordance with the rules for major, minor, and patch versions.