From f48e8f857cc7ad97ea34dd462931008ef687b1c9 Mon Sep 17 00:00:00 2001 From: Sergey Konstantinov Date: Sun, 9 Apr 2023 22:26:49 +0300 Subject: [PATCH] style fix & clarifications --- docs/API.en.epub | Bin 1160870 -> 1160926 bytes docs/API.en.html | 131 +++++++++--------- docs/API.en.pdf | Bin 7052045 -> 7058640 bytes docs/API.ru.epub | Bin 1239216 -> 1239091 bytes docs/API.ru.html | 19 ++- docs/API.ru.pdf | Bin 7332331 -> 7336004 bytes .../02-Section I. The API Design/05.md | 2 +- .../04-Section III. The API Product/07.md | 18 +-- .../04-Section III. The API Product/08.md | 31 +++-- .../04-Section III. The API Product/09.md | 28 ++-- .../04-Section III. The API Product/10.md | 18 +-- .../04-Section III. The API Product/11.md | 16 +-- .../04-Section III. The API Product/12.md | 6 +- .../04-Section III. The API Product/13.md | 10 +- .../04-Раздел III. API как продукт/08.md | 10 +- .../04-Раздел III. API как продукт/09.md | 6 +- .../04-Раздел III. API как продукт/13.md | 4 +- 17 files changed, 149 insertions(+), 150 deletions(-) diff --git a/docs/API.en.epub b/docs/API.en.epub index 91a517cffc2fe05e086aec5444df165f918b426a..18edb27f5824bf95e32d66b9e2973ed1de58a9df 100644 GIT binary patch delta 40768 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%0DQ(5uc7~f?)**dE}{D%5m^Ks6` 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

*NcqF&a(U!lHN*aZr;h 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 diff --git a/docs/API.en.html b/docs/API.en.html index 1da8f35..f6c4693 100644 --- a/docs/API.en.html +++ b/docs/API.en.html @@ -2494,7 +2494,7 @@ X-Idempotency-Token: <idempotency token>

NB: in this book, we often use short identifiers like "123" in code examples; that's for the convenience of reading the book on small screens. Do not replicate this practice in a real-world API.

23. Stipulate Future Restrictions

With the API popularity growth, it will inevitably become necessary to introduce technical means of preventing illicit API usage, such as displaying captchas, setting honeypots, raising the “too many requests” exceptions, installing anti-DDoS proxies, etc. All these things cannot be done if the corresponding errors and messages were not described in the docs from the very beginning.

-

You are not obliged to actually generate those exceptions, but you might stipulate this possibility in the terms of service. For example, you might describe the 429 Too Many Requests error or captcha redirect but implement the functionality when it's actually needed.

+

You are not obliged to actually generate those exceptions, but you might stipulate this possibility in the Terms of Service (ToS). For example, you might describe the 429 Too Many Requests error or captcha redirect but implement the functionality when it's actually needed.

It is extremely important to leave room for multi-factored authentication (such as TOTP, SMS, or 3D-secure-like technologies) if it's possible to make payments through the API. In this case, it's a must-have from the very beginning.

24. No Bulk Access to Sensitive Data

If it's possible to get through the API users' personal data, bank card numbers, private messages, or any other kind of information, exposing which might seriously harm users, partners, and/or you — there must be no methods of bulk getting the data, or at least there must be rate limiters, page size restrictions, and, ideally, multi-factored authentication in front of them.

@@ -3624,7 +3624,7 @@ ProgramContext.dispatch = (action) => {

Different companies employ different approaches to determining the granularity of API services, e.g. what is counted as a separate product and what is not. To some extent, this is a matter of convenience and taste judgment. Consider splitting an API into parts if:

  • it makes sense for partners to integrate only one API part, e.g. some isolated subset of the API provides enough means to solve users' problems;
  • -
  • API parts might be versioned separately and independently, and it is meaningful from the partners' point of view (this usually means that those “isolated” APIs are either fully independent or maintain strict backwards compatibility and introduce new major versions only when it's absolutely necessary; otherwise, maintaining a matrix which API No. 1 version is compatible with which API No. 2 version will soon become a catastrophe);
  • +
  • API parts might be versioned separately and independently, and it is meaningful from the partners' point of view (this usually means that those “isolated” APIs are either fully independent or maintain strict backwards compatibility and introduce new major versions only when it's absolutely necessary; otherwise, maintaining a matrix which API #1 version is compatible with which API #2 version will soon become a catastrophe);
  • it makes sense to set tariffs and limits for each API service independently;
  • the auditory of the API segments (either developers, business owners, or end users) is not overlapping, and “selling” granular API to customers is much easier than aggregated.
@@ -3651,16 +3651,19 @@ ProgramContext.dispatch = (action) => {

In general, you should aim to have each partner using the API services in a manner that maximizes your profit as an API vendor. Where the partner doesn't try to make some unique experience and needs just a typical solution, you would benefit from making them use widgets, which are under your full control and thus ease the API version fragmentation problem and allow for experimenting in order to reach your KPIs. Where the partner possesses some unique expertise in the subject area and develops a unique service on top of your API, you would benefit from allowing full freedom in customizing the integration, so they might cover specific market niches and enjoy the advantage of offering more flexibility compared to services using competing APIs.

Chapter 26. The API Key Performance Indicators 

As we described in the previous chapters, there are many API monetization models, both direct and indirect. Importantly, most of them are fully or conditionally free for partners, and the direct-to-indirect benefits ratio tends to change during the API lifecycle. That naturally leads us to the question of how exactly shall we measure the API success and what goals are to be set for the product team.

Of course, the most explicit metric is money: if your API is monetized directly or attracts visitors to a monetized service, the rest of the chapter will be of little interest to you, maybe just as a case study. If, however, the contribution of the API to the company's income cannot be simply measured, you have to stick to other, synthetic, indicators.

-

The obvious key performance indicator (KPI) No. 1 is the number of end users and the number of integrations (i.e. partners using the API). Normally, they are in some sense a business health barometer: if there is a normal competitive situation among the API suppliers, and all of them are more or less in the same position, then the figure of how many developers (and consequently, how many end users) are using the API is the main metric of the success of the API product.

-

However, sheer numbers might be deceiving, especially if we talk about free-to-use integrations. There are several factors that twist the statistics:

+

The obvious key performance indicator (KPI) #1 is the number of end users and the number of integrations (i.e. partners using the API). Normally, they are in some sense a business health barometer: if there is a normal competitive situation among the API suppliers, and all of them are more or less in the same position, then the figure of how many developers (and consequently, how many end users) are using the API is the main metric of success of the API product.

+

However, sheer numbers might be deceiving, especially if we talk about free-to-use integrations. There are several factors that make them less reliable:

  • -

    the high-level API services that are meant for straightforward integration (see the previous chapter) are significantly distorting the statistics if the competitors don't provide such services; typically, for one full-scale integration there will be tens, maybe hundreds, of those lightweight embedded widgets; thereby, it's crucial to have partners counted for each kind of the integration independently;

    +

    the high-level API services that are meant for point-and-click integration (see the previous chapter) are significantly distorting the statistics, especially if the competitors don't provide such services; typically, for one full-scale integration there will be tens, maybe hundreds, of those lightweight embedded widgets;

    +
      +
    • thereby, it's crucial to have partners counted for each kind of the integration independently;
    • +
  • partners tend to use the API in suboptimal ways:

      -
    • embed it at every site page / application screen instead of only those where end users can really interact with the API;
    • +
    • embed it at every website page / application screen instead of only those where end users can really interact with the API;
    • put widgets somewhere deep in the page / screen footer, or hide it behind spoilers;
    • initialize a broad range of API modules, but use only a limited subset of them;
    @@ -3684,10 +3687,10 @@ ProgramContext.dispatch = (action) => {
  • the definition of target action depends on the monetization model and might be quite straightforward (like the number of paying partners, or the number of paid ad clicks) or, to the contrary, pretty implicit (like the growth of the company's developer blog auditory).

SLA

-

This chapter would be incomplete if we didn't mention the “hygienic” KPI — the service level and the service availability. We won't be describing the concept in detail, as the API SLA isn't any different from any other digital services SLAs. Let us point out that this metric must be tracked, especially if we talk about pay-to-use APIs. However, in many cases, API vendors prefer to offer rather loose SLAs, treating the provided functionality as data access or a content licensing service.

+

This chapter would be incomplete if we didn't mention the “hygienic” KPI — the service level and the service availability. We won't be describing the concept in detail, as the API SLA isn't any different from any other digital services SLAs. Let us just state that this metric must be tracked, especially if we talk about pay-to-use APIs. However, in many cases, API vendors prefer to offer rather loose SLAs, treating the provided functionality as a data access or content licensing service.

Still, let us re-iterate once more: any problems with your API are automatically multiplied by the number of partners you have, especially if the API is vital for them, e.g. the API outage makes the main functionality of their services unavailable. (And actually, because of the above-mentioned reasons, the average quality of integrations implies that partners' services will suffer even if the availability of the API is not formally speaking critical for them, but because developers use it excessively and do not bother with proper error handling.)

-

It is important to mention that predicting the workload for the API service is rather complicated. Sub-optimal API usage, e.g. initializing the API in those application and website parts where it's not actually needed, might lead to a colossal increase in the number of requests after changing a single line of partner's code. The safety margin for an API service must be much higher than for a regular service for end users — it must survive the situation of the largest partner suddenly starting querying the API on every page and every application screen. (If the partner is already doing that, then the API must survive doubling the load: imagine the partner accidentally starts initializing the API twice on each page / screen.)

-

Another extremely important hygienic minimum is the informational security of the API service. In the worst-case scenario, namely, if an API service vulnerability allows for exploiting partner applications, one security loophole will in fact be exposed in every partner application. Needless to say that the cost of such a mistake might be overwhelmingly colossal, even if the API itself is rather trivial and has no access to sensitive data (especially if we talk about webpages where no “sandbox” for third-party scripts exists, and any piece of code might let's say track the data entered in forms). API services must provide the maximum protection level (for example, choose cryptographical protocols with a certain overhead) and promptly react to any messages regarding possible vulnerabilities.

+

It is important to mention that predicting the workload for the API service is rather complicated. Sub-optimal API usage, e.g. initializing the API in those application and website parts where it's not actually needed, might lead to a colossal increase in the number of requests after changing a single line of partner's code. The safety margin for an API service must be much higher than for a regular service for end users — it must survive the situation of the largest partner suddenly starting querying the API on every page and every application screen. (If the partner is already doing that, then the API must survive doubling the load if the partner by accident starts initializing the API twice on each page / screen.)

+

Another extremely important hygienic minimum is the informational security of the API service. In the worst-case scenario, namely, if an API service vulnerability allows for exploiting partner applications, one security loophole will in fact be exposed in every partner application. Needless to say that the cost of such a mistake might be overwhelmingly colossal, even if the API itself is rather trivial and has no access to sensitive data (especially if we talk about webpages where no “sandbox” for third-party scripts exists, and any piece of code might let's say track the data entered in forms). API services must provide the maximum protection level (for example, choose cryptographical protocols with a certain overhead) and promptly react to any reports regarding possible vulnerabilities.

Comparing to Competitors

While measuring KPIs of any service, it's important not only to evaluate your own numbers but also to match them against the state of the market:

    @@ -3695,13 +3698,13 @@ ProgramContext.dispatch = (action) => {
  • is your service growing faster than the market itself or is the rate the same, or is it even less?
  • what proportion of the growth is caused by the growth of the market, and what is related to your efforts?
-

Getting answers to those questions might be quite non-trivial in the case of API services. Indeed, how could you learn how many integrations has your competitor had during the same period of time, and what number of target actions had happened on their platform? Sometimes, the providers of popular analytical tools might help you with this, but usually, you have to monitor the potential partners' apps and websites and gather the statistics regarding APIs they're using. The same applies to market research: unless your niche is significant enough for some analytical company to conduct market research, you will have to either commission such a study or make your own estimations — conversely, through interviewing potential customers.

Chapter 27. Identifying Users and Preventing Fraud 

+

Getting answers to those questions might be quite non-trivial in the case of API services. Indeed, how could you learn how many integrations has your competitor had during the same period of time, and what number of target actions had happened on their platform? Sometimes, the providers of popular analytical tools might help you with this, but usually, you have to monitor the potential partners' apps and websites and gather the statistics regarding APIs they're using. The same applies to market research: unless your niche is significant enough for some analytical company to conduct a study, you will have to either commission such work or make your own estimations — conversely, through interviewing potential customers.

Chapter 27. Identifying Users and Preventing Fraud 

In the context of working with an API, we talk about two kinds of users of the system:

  • users-developers, e.g. your partners writing code atop of the API;
  • end users interacting with applications implemented by the users-developers.
-

In most cases, you need to have both of them identified (in a technical sense: discern one unique visitor from another) to have answers to the following questions:

+

In most cases, you need to have both of them identified (in a technical sense: discern one unique customer from another) to have answers to the following questions:

  • how many users are interacting with the system (simultaneously, daily, monthly, and yearly)?
  • how many actions does each user make?
  • @@ -3715,22 +3718,22 @@ ProgramContext.dispatch = (action) => {

    In the case of commercial APIs, the quality and timeliness of gathering this data are twice that important, as the tariff plans (and therefore the entire business model) depend on it. Therefore, the question of how exactly we're identifying users is crucial.

    Identifying Applications and Their Owners

    Let's start with the first user category, e.g. API business partners-developers. The important remark: there are two different entities we must learn to identify, namely applications and their owners.

    -

    An application is roughly speaking a logically separate case of API usage, usually — literally an application (mobile or desktop one) or a website, e.g. some technical entity. Meanwhile, an owner is a legal body that you have the API usage agreement signed with, e.g. a legal body. if API tariffs imply some limits and/or tariffs depend on the type of the service or the way it uses the API, this automatically means the necessity to track one owner's applications separately.

    +

    An application is roughly speaking a logically separate case of API usage, usually — literally an application (mobile or desktop one) or a website, e.g. some technical entity. Meanwhile, an owner is a legal body that you have the API usage agreement signed. If API Terms of Service (ToS) imply different limits and/or tariffs depending on the type of the service or the way it uses the API, this automatically means the necessity to track one owner's applications separately.

    In the modern world, the factual standard for identifying both entities is using API keys: a developer who wants to start using an API must obtain an API key bound to their contact info. Thus the key identifies the application while the contact data identifies the owner.

    Though this practice is universally widespread we can't but notice that in most cases it's useless, and sometimes just destructive.

    Its general advantage is the necessity to supply actual contact info to get a key, which theoretically allows for contacting the application owner if needed. (In the real world, it doesn't work: key owners often don't read mailboxes they provided upon registration; and if the owner is a company, it easily might be a no-one's mailbox or a personal email of some employee that left the company a couple of years ago.)

    The main disadvantage of using API keys is that they don't allow for reliably identifying both applications and their owners.

    If there are free limits to API usage, there is a temptation to obtain many API keys bound to different owners to fit those free limits. You may raise the bar of having such multi-accounts by requiring, let's say, providing a phone number or bank card data, but there are popular services for automatically issuing both. Paying for a virtual SIM or credit card (to say nothing about buying the stolen ones) will always be cheaper than paying the proper API tariff — unless it's the API for creating those cards. Therefore, API key-based user identification (if you're not requiring the physical contract to be signed) does not mean you don't need to double-check whether users comply with the terms of service and do not issue several keys for one app.

    -

    Another problem is that an API key might be simply stolen from a lawful partner; in the case of client or web applications, that's quite trivial.

    -

    It might look like the problem is not that important in the case of server-to-server integrations, but it actually is. Imagine that a partner provides a public service of their own that uses your API under the hood. That usually means there is an endpoint in the partner's backend that performs a request to the API and returns the result, and this endpoint perfectly suits as a free replacement of the API access to a cybercriminal. Of course, you might say this fraud is a problem of partners', but, first, it would be naïve to expect each partner develops their own anti-fraud system, and, second, it's just sub-optimal: obviously, a centralized anti-fraud system would be way more effective than a bunch of amateur implementations. Also, server keys might also be stolen: it's much harder than stealing client keys but doable. With any popular API, sooner or later you will face the situation of stolen keys made available to the public (or a key owner just shares it with acquaintances out of the kindness of their heart).

    +

    Another problem is that an API key might be simply stolen from a lawful partner; in the case of mobile or web applications, that's quite trivial.

    +

    It might look like the problem is not that important in the case of server-to-server integrations, but it actually is. Imagine that a partner provides a public service of their own that uses your API under the hood. That usually means there is an endpoint in the partner's backend that performs a request to the API and returns the result, and this endpoint perfectly suits as a free replacement of direct access to the API for a cybercriminal. Of course, you might say this fraud is a problem of partners', but, first, it would be naïve to expect each partner develops their own anti-fraud system, and, second, it's just sub-optimal: obviously, a centralized anti-fraud system would be way more effective than a bunch of amateur implementations. Also, server keys might also be stolen: it's much harder than stealing client keys but doable. With any popular API, sooner or later you will face the situation of stolen keys made available to the public (or a key owner just shared it with acquaintances out of the kindness of their heart).

    One way or another, a problem of independent validation arises: how can we control whether the API endpoint is requested by a user in compliance with the terms of service?

    -

    Mobile applications might be conveniently tracked through their identifiers in the corresponding store (Google Play, App Store, etc.), so it makes sense to require this identifier to be passed by partners as an API initialization parameter. Websites with some degree of confidence might be identified by the Referer and Origin HTTP headers.

    +

    Mobile applications might be conveniently tracked through their identifiers in the corresponding store (Google Play, App Store, etc.), so it makes sense to require this identifier to be passed by partners as an API initialization parameter. Websites with some degree of confidence might be identified by the Referer and Origin HTTP headers.

    This data is not itself reliable, but it allows for making cross-checks:

      -
    • if the key was issued for one specific domain but requests are coming with a different Referer, it makes sense to investigate the situation and maybe ban the possibility to access the API with this Referer or this key;
    • -
    • if an application initializes API by providing the key registered to another application, it makes sense to contact the store administration and ask for removing one of the apps.
    • +
    • if a key was issued for one specific domain but requests are coming with a different Referer, it makes sense to investigate the situation and maybe ban the possibility to access the API with this Referer or this key;
    • +
    • if an application initializes API by providing a key registered to another application, it makes sense to contact the store administration and ask for removing one of the apps.
    -

    NB: don't forget to set infinite limits for using the API with the localhost, 127.0.0.1 / [::1] Referers, and also for your own sandbox if it exists. Yes, abusers will sooner or later learn this fact and will start using it, but otherwise, you will ban local development and your own website much sooner than that.

    +

    NB: don't forget to set infinite limits for using the API with the localhost, 127.0.0.1 / [::1] Referers, and also for your own sandbox if it exists. Yes, abusers will sooner or later learn this fact and will start exploiting it, but otherwise, you will ban local development and your own website much sooner than that.

    The general conclusion is:

    • it is highly desirable to have partners formally identified (either through obtaining API keys or by providing contact data such as website domain or application identifier in a store while initializing the API);
    • @@ -3741,21 +3744,23 @@ ProgramContext.dispatch = (action) => {
      1. The most simple and obvious indicator is an IP address. It's very hard to counterfeit them (e.g. the API server always knows the remote address), and the IP address statistics are reasonably demonstrative.

        -

        If the API is provided as a server-to-server one, there will be no access to the end user's IP address. However, it makes sense to require partners to propagate the IP address (for example, in a form of the X-Forwarder-For header) — among other things, to help partners fight fraud and unintended usage of the API.

        -

        Until recently, IP addresses were also a convenient statistics indicator because it was quite expensive to get a large pool of unique addresses. However, with ipv6 advancement this restriction is no longer actual; ipv6 rather put the light on the fact that you can't just count unique addresses — the aggregates are to be tracked: -* the cumulative number of requests by networks, e.g. the hierarchical calculations (the number of /8, /16, /24, etc. networks) -* the cumulative statistics by autonomous networks (AS); -* the API requests through known public proxies and TOR network.

        -

        An abnormal number of requests in one network might be evidence of the API being actively used inside some corporative environment (or in this region NATs are widespread).

        +

        If the API is provided as a server-to-server one, there will be no access to the end user's IP address. However, it makes sense to require partners to propagate the IP address (for example, in a form of the X-Forwarded-For header) — among other things, to help partners fight fraud and unintended usage of the API.

        +

        Until recently, IP addresses were also a convenient statistics indicator because it was quite expensive to get a large pool of unique addresses. However, with ipv6 advancement this restriction is no longer actual; ipv6 rather put the light on the fact that you can't just count unique addresses — the aggregates are to be tracked:

        +
          +
        • the cumulative number of requests by networks, e.g. the hierarchical calculations (the number of /8, /16, /24, etc. networks)
        • +
        • the cumulative statistics by autonomous networks (AS);
        • +
        • the API requests through known public proxies and TOR network.
        • +
        +

        An abnormal number of requests in one network might be evidence of the API being actively used inside some corporative environment (or NATs being widespread in the region).

      2. -

        Additional means of tracking are users' unique identifiers, most notably cookies. However, most recently this method of gathering data is under attack from several sides: browser makers restrict third-party cookies, users are employing anti-tracker software, and lawmakers started to roll out legal requirements against data collection. In the current situation, it's much easier to drop cookie usage than to be compliant with all the regulations.

        +

        Additional means of tracking are users' unique identifiers, most notably cookies. However, most recently this method of gathering data got attacked from several directions: browser makers restrict third-party cookies, users are employing anti-tracker software, and lawmakers started to roll out legal requirements against data collection. In the current situation, it's much easier to drop cookie usage than to be compliant with all the regulations.

        All this leads to a situation when public APIs (especially those installed on free-to-use sites and applications) are very limited in the means of collecting statistics and analyzing user behavior. And that impacts not only fighting all kinds of fraud but analyzing use cases as well. That's the way.

      NB. In some jurisdictions, IP addresses are considered personal data, and collecting them is prohibited as well. We don't dare to advise on how an API vendor might at the same time be able to fight prohibited content on the platform and don't have access to users' IP addresses. We presume that complying with such legislation implies storing statistics by IP address hashes. (And just in case we won't mention that building a rainbow table for SHA-256 hashes covering the entire 4-billion range of IPv4 addresses would take several hours on a regular office-grade computer.)

      Chapter 28. The Technical Means of Preventing ToS Violations 

      Implementing the paradigm of a centralized system of preventing partner endpoints-bound fraud, which we described in the previous chapter, in practice faces non-trivial difficulties.

      -

      The task of filtering out illicit API requests generally comprises three steps:

      +

      The task of filtering out illicit API requests comprises three steps:

      • identifying suspicious users;
      • optionally, asking for an additional authentication factor;
      • @@ -3763,40 +3768,40 @@ ProgramContext.dispatch = (action) => {
      1. Identifying Suspicious Users

      Generally speaking, there are two approaches we might take, the static one and the dynamic (behavioral) one.

      -

      Statically we monitor suspicions activity surges, as described in the previous chapter, marking an unusually high density of requests coming from specific networks or Referer's (actually, any piece of information suits if it divides users into more or less independent groups: for example, OS version or system language if you can gather those).

      +

      Statically we monitor suspicions activity surges, as described in the previous chapter, marking an unusually high density of requests coming from specific networks or Referers (actually, any piece of information suits if it splits users into more or less independent groups: for example, OS version or system language would suffice if you can gather those).

      Behavioral analysis means we're examining the history of requests made by a specific user, searching for non-typical patterns, such as “unhuman” order of traversing endpoints or too small pauses between requests.

      -

      Importantly, when we talk about “user,” we will have to make a second analytical contour to work with IP addresses, as malefactors aren't obliged to preserve cookies or other identification tokens, or will keep a pool of such tokens to impede their exposure.

      +

      Importantly, when we talk about “users,” we will have to make duplicate systems to observe them both using tokens (cookies, logins, phone numbers) and IP addresses, as malefactors aren't obliged to preserve the tokens between requests, or might keep a pool of them to impede their exposure.

      2. Requesting an Additional Authentication Factor

      As both static and behavioral analyses are heuristic, it's highly desirable to not make decisions based solely on their outcome but rather ask the suspicious users to additionally prove they're making legitimate requests. If such a mechanism is in place, the quality of an anti-fraud system will be dramatically improved, as it allows for increasing system sensitivity and enabling pro-active defense, e.g. asking users to pass the tests in advance.

      In the case of services for end users, the main method of acquiring the second factor is redirecting to a captcha page. In the case of APIs it might be problematic, especially if you initially neglected the “Stipulate Restrictions” rule we've given in the “Describing Final Interfaces” chapter. In many cases, you will have to impose this responsibility on partners (e.g. it will be partners who show captchas and identify users based on the signals received from the API endpoints). This will, of course, significantly impair the convenience of working with the API.

      NB. Instead of captcha, there might be other actions introducing additional authentication factors. It might be the phone number confirmation or the second step of the 3D-Secure protocol. The important part is that requesting an additional authentication step must be stipulated in the program interface, as it can't be added later in a backwards-compatible manner.

      -

      Other popular mechanics of identifying robots include offering a bait (“honeypot”) or employing the execution environment checks (starting from rather trivial like executing JavaScript on the webpage and ending with sophisticated techniques of checking application integrity).

      +

      Other popular mechanics of identifying robots include offering a bait (“honeypot”) or employing the execution environment checks (starting from rather trivial ones like executing JavaScript on the webpage and ending with sophisticated techniques of checking application integrity checksums).

      3. Restricting Access
      -

      The illusion of having a broad choice of technical means of identifying fraud users should not deceive you as you will soon discover the lack of effective methods of restricting those users. Banning them by cookie / Referer / User-Agent makes little to no impact as this data is supplied by clients, and might be easily forged. In the end, you have four mechanisms for suppressing illegal activities:

      +

      The illusion of having a broad choice of technical means of identifying fraud users should not deceive you as you will soon discover the lack of effective methods of restricting those users. Banning them by cookie / Referer / User-Agent makes little to no impact as this data is supplied by clients, and might be easily forged. In the end, you have four mechanisms for suppressing illegal activities:

        -
      • banning users by IP (networks, autonomous systems);
      • -
      • requiring mandatory user identification (maybe layered: login / login with confirmed phone number / login with confirmed identity / login with confirmed identity and biometrics / etc.);
      • -
      • returning fake responses;
      • +
      • banning users by IP (networks, autonomous systems)
      • +
      • requiring mandatory user identification (maybe tiered: login / login with confirmed phone number / login with confirmed identity / login with confirmed identity and biometrics / etc.)
      • +
      • returning fake responses
      • filing administrative abuse reports.
      -

      The problem with option number one is the collateral damage you will inflict, especially if you have to ban subnets.

      +

      The problem with the first option is the collateral damage you will inflict, especially if you have to ban subnets.

      The second option, though quite rational, is usually inapplicable to real APIs, as not every partner will agree with the approach, and definitely not every end user. This will also require being compliant with the existing personal data laws.

      The third option is the most effective one in technical terms as it allows to put the ball in the malefactor's court: it is now them who need to invent how to learn if the robot was detected. But from the moral point of view (and from the legal perspective as well) this method is rather questionable, especially if we take into account the probability of false-positive signals, meaning that some real users will get the fake data.

      Thereby, you have only one method that really works: filing complaints to hosting providers, ISPs, or law enforcement authorities. Needless to say, this brings certain reputational risks, and the reaction time is rather not lightning fast.

      -

      In most cases, you're not fighting fraud — you're actually increasing the cost of the attack, simultaneously buying yourself enough time to make administrative moves against the perpetrator. Preventing API misusage completely is impossible as malefactors might ultimately employ the expensive but bulletproof solution — to hire real people to make the requests to the API on real devices through legal applications.

      -

      An opinion exists, which the author of this book shares, that engaging in this sword-against-shield confrontation must be carefully thought out, and advanced technical solutions are to be enabled only if you are one hundred percent sure it is worth it (e.g. if they steal real money or data). By introducing elaborate algorithms, you rather conduct an evolutional selection of the smartest and most cunning cybercriminals, counteracting who will be way harder than those who just naively call API endpoints with curl. What is even more important, in the final phase — e.g. when filing the complaint to authorities — you will have to prove the alleged ToS violation, and doing so against an advanced fraudster will be problematic. So it's rather better to have all the malefactors monitored (and regularly complained against), and escalate the situation (e.g. enable the technical protection and start legal actions) only if the threat passes a certain threshold. That also implies that you must have all the tools ready, and just keep them below fraudsters' radars.

      +

      In most cases, you're not fighting fraud — you're actually increasing the cost of the attack, simultaneously buying yourself enough time to make administrative moves against the perpetrator. Preventing API misusage completely is impossible as malefactors might ultimately employ the expensive but bulletproof solution — to hire real people to make the requests to the API on real devices through legitimate applications.

      +

      An opinion exists, which the author of this book shares, that engaging in this sword-against-shield confrontation must be carefully thought out, and advanced technical solutions are to be enabled only if you are one hundred percent sure it is worth it (e.g. if they steal real money or data). By introducing elaborate algorithms, you rather conduct an evolutional selection of the smartest and most cunning cybercriminals, counteracting to whom will be way harder than to those who just naïvely call API endpoints with curl. What is even more important, in the final phase — e.g. when filing the complaint to authorities — you will have to prove the alleged ToS violation, and doing so against an advanced fraudster will be problematic. So it's rather better to have all the malefactors monitored (and regularly complained against), and escalate the situation (e.g. enable the technical protection and start legal actions) only if the threat passes a certain threshold. That also implies that you must have all the tools ready, and just keep them below fraudsters' radars.

      Out of the author of this book's experience, the mind games with malefactors, when you respond to any improvement of their script with the smallest possible effort that is enough to break it, might continue indefinitely. This strategy, e.g. making fraudsters guess which traits were used to ban them this time (instead of unleashing the whole heavy artillery potential), annoys amateur “hackers” greatly as they lack hard engineering skills and just give up eventually.

      Dealing with Stolen Keys

      Let's now move to the second type of unlawful API usage, namely using in the malefactor's applications keys stolen from conscientious partners. As the requests are generated by real users, captcha won't help, though other techniques will.

      1. -

        Maintaining metrics collection by IP addresses and subnets might be of use in this case as well. If the malefactor's app isn't a public one but rather targeted to some closed audience, this fact will be visible in the dashboards (and if you're lucky enough, you might also find suspicious Referers, public access to which is restricted).

        +

        Maintaining metrics collection by IP addresses and subnets might be of use in this case as well. If the malefactor's app isn't a public one but rather targeted to some closed audience, this fact will be visible in the dashboards (and if you're lucky enough, you might also find suspicious Referers, public access to which is restricted).

      2. Allowing partners to restrict the functionality available under specific API keys:

        • -

          setting the allowed IP address range for server-to-server APIs, allowed Referer's and application ids for client APIs;

          +

          setting the allowed IP address range for server-to-server APIs, allowed Referers and application ids for client APIs;

        • white-listing only allowed API functions for a specific key;

          @@ -3813,7 +3818,7 @@ ProgramContext.dispatch = (action) => {

          for example, if on the partner's website, there is a form displaying the best lungo offers, for which the partners call the API endpoint like /v1/search?recipe=lungo&api_key={apiKey}, then the API key might be replaced with a signature like sign = HMAC("recipe=lungo", apiKey); the signature might be stolen as well, but it will be useless for malefactors as they will be able to find only lungo with it;

        • -

          instead of API keys, time-based one-time passwords (TOTP) might be used; these tokens are valid for a short period of time (usually, one minute) only, which makes working with stealing keys much more sophisticated.

          +

          instead of API keys, time-based one-time passwords (TOTP) might be used; these tokens are valid for a short period of time only (typically, one minute), which makes using stolen keys much more complicated.

      3. @@ -3824,7 +3829,7 @@ ProgramContext.dispatch = (action) => {

        Banning compromised API keys; the partners' reaction will be, of course, negative, but ultimately every business will prefer temporary disabling of some functionality over getting a multi-million bill.

      Chapter 29. Supporting customers 

      -

      First of all, an important remark: when we talk about supporting API customers, we mean supporting developers and to some extent business partners. End users seldom interact with APIs directly, with an exception of several non-standard cases.

      +

      From banning users, let's change the topic to supporting them. First of all, an important remark: when we talk about supporting API customers, we mean helping developers and to some extent business partners. End users seldom interact with APIs directly, with an exception of several non-standard cases:

      1. If you can't reach partners that are using the API incorrectly, you might have to display errors that end users can see. This might happen if the API was provided for free and with minimum partner identification requirements while in the growth phase, and then the conditions changed (a popular API version is no longer supported or became paid).

        @@ -3844,28 +3849,28 @@ ProgramContext.dispatch = (action) => {

    The former is of course extremely important for any healthy service (including APIs) but again bears little API-related specifics. In the context of this book, we are much more interested in the latter.

    As an API is a program product, developers will be in fact asking how this specific piece of code that they have written works. This fact raises the level of required customer support staff members' expertise quite high as you need a software engineer to read the code and understand the problem. But this is but half of the problem; another half is, as we have mentioned in the previous chapters, that most of these questions will be asked by inexperienced or amateur developers. In a case of a popular API, it means that 9 out of 10 inquiries will not be about the API. Less skilled developers lack language knowledge, their experience with the platform is fragmented, and they can't properly formulate their problem (and therefore search for an answer on the Internet before contacting support; though, let us be honest, they usually don't even try).

    -

    There are several options for tackling these issues.

    +

    There are several options for tackling these issues:

    1. -

      The most user-friendly scenario is hiring people with basic technical skills as the first line of support. These employees must possess enough expertise in understanding how the API works to be able to identify those unrelated questions and respond to them according to some FAQ, point out to the relevant external resource (let's say, the support service of the platform or the community forum of the programming language), or redirect relevant issues to the API developers.

      +

      The most user-friendly scenario is hiring people with basic technical skills as the first line of support. These employees must possess enough expertise in understanding how the API works to be able to identify those unrelated questions and respond to them according to some FAQ, point out to a relevant external resource (let's say, the support service of the OS or the community forum of the programming language) if the problem is not related to the API itself, and redirect relevant issues to the API developers.

    2. -

      The inverse scenario: partners must pay for technical support, and it's the API developers who answer the questions. It doesn't actually make a significant difference in terms of the quality of the issues (it's still inexperienced developers who use the API and ask questions; you will just cut off those who can't afford paid support) but at least you won't have a hiring problem as you might allow yourself the luxury of hiring engineers for the first line of support.

      +

      The inverse scenario: partners must pay for technical support, and it's the API developers who answer the questions. It doesn't actually make a significant difference in terms of the quality of the issues (it's still mostly inexperienced developers who can't solve the problem on their own; you will just cut off those who can't afford paid support) but at least you won't have a hiring problem as you might allow yourself the luxury of having engineers for the first line of support.

    3. Partly (or, sometimes, fully) the developer community might help with solving the amateur problems (see the “Communicating with Developers” chapter). Usually, community members are pretty capable of answering those questions, especially if moderators help them.

    -

    Importantly, whatever options you choose, it's still the API developers in the second line of support simply because only they can fully understand the problem and the partners' code. That implies two important consequences.

    +

    Importantly, whatever options you choose, it's still the API developers in the second line of support simply because only they can fully understand the problem and the partners' code. That implies two important consequences:

    1. -

      You must consider the time needed to investigate inquiries while planning the API development team time. Reading unfamiliar code and remote debugging are very hard and exhausting tasks. The more functionality you expose and the more platforms you support, the more load is put on the team in terms of dealing with support tickets.

      +

      You must take into account working with inquiries while planning the API development team time. Reading unfamiliar code and remote debugging are very hard and exhausting tasks. The more functionality you expose and the more platforms you support, the more load is put on the team in terms of dealing with support tickets.

    2. -

      As a rule, developers are totally not happy with the perspective of sorting the incoming requests and answering them. The first line of support will still let through a lot of dilettante or badly formulated questions, and that will annoy on-duty API developers. There are several approaches to mitigate the problem:

      +

      As a rule, developers are totally not happy about the perspective of coping with incoming requests and answering them. The first line of support will still let through a lot of dilettante or badly formulated questions, and that will annoy on-duty API developers. There are several approaches to mitigate the problem:

      • -

        try to find people with a customer-oriented mindset, who like this activity, and encourage them (including financial stimulus) to deal with support; it might be someone on the team (and not necessarily a developer) or some active community member;

        +

        try to find people with a customer-oriented mindset, who like this activity, and encourage them (including financial stimulus) to perform support functions; it might be someone on the team (and not necessarily a developer) or some active community member;

      • the remaining load must be distributed among the developers equally and fairly, up to introducing the duty calendar.

        @@ -3875,7 +3880,7 @@ ProgramContext.dispatch = (action) => {

    And of course, analyzing the questions is a useful exercise to populate FAQs and improve the documentation and the first-line support scripts.

    External Platforms

    -

    Sooner or later, you will find that customers ask their questions not only through the official channels, but also on numerous Internet-based forums, starting from those specifically created for this, like StackOverflow, and ending with social networks and personal blogs. It's up to you whether to spend time searching for such inquiries; we would rather recommend providing support through those sites that have convenient tools for that (like subscribing to specific tags).

    Chapter 30. The Documentation 

    +

    Sooner or later, you will find that customers ask their questions not only through the official channels, but also on numerous Internet-based forums, starting from those specifically created for this, like StackOverflow, and ending with social networks and personal blogs. It's up to you whether to spend time searching for such inquiries. We would rather recommend providing support through those platforms that have convenient tools for that (like subscribing to specific tags).

    Chapter 30. The Documentation 

    Regretfully, many API providers pay miserable attention to the quality of documentation. Meanwhile, the documentation is the face of the product and the entry point to it. The problem becomes even worse if we acknowledge that it's almost impossible to write the help docs the developers will consider at least satisfactory.

    Before we start describing documentation types and formats, we should stress one important statement: developers interact with your help articles totally unlike you expect them to. Remember yourself working on the project: you make quite specific actions.

      @@ -3884,13 +3889,13 @@ ProgramContext.dispatch = (action) => {

    In fact, newcomers (e.g. those developers who are not familiar with the API) usually want just one thing: to assemble the code that solves their problem out of existing code samples and never return to this issue again. Sounds not exactly reassuringly, given the amount of work invested into the API and its documentation development, but that's what the reality looks like. Also, that's the root cause of developers' dissatisfaction with the docs: it's literally impossible to have articles covering exactly that problem the developer comes with being detailed exactly to the extent the developer knows the API concepts. In addition, non-newcomers (e.g. those developers who have already learned the basics concepts and are now trying to solve some advanced problems) do not need these “mixed examples” articles as they look for some deeper understanding.

    Introductory Notes

    -

    Documentation frequently suffers from being excessively clerical; it's being written using formal terminology (which often requires reading the glossary before the actual docs) and being unreasonably inflated. So instead of a two-word answer to the user's question a couple of paragraphs are conceived — a practice we strongly disapprove of. The perfect documentation must be simple and laconic, and all the terms must be either explained in the text or given a reference to such an explanation. However, “simple” doesn't mean “illiterate”: remember, the documentation is the face of your product, so grammar errors and improper usage of terms are unacceptable.

    -

    Also, keep in mind that documentation will be used for searching as well, so every page should contain all the keywords required to be properly ranked by search engines. This requirement somehow contradicts the simple-and-laconic principle; that's the way.

    +

    Documentation frequently suffers from being excessively clerical; it's being written using formal terminology (which often requires reading the glossary before the actual docs) and is frequently unreasonably inflated. So instead of a two-word answer to a user's question, a couple of paragraphs is conceived — a practice we strongly disapprove of. The perfect documentation must be simple and laconic, and all the terms must be either explained in the text or given a reference to such an explanation. However, “simple” doesn't mean “illiterate”: remember, the documentation is the face of your product, so grammar errors and improper usage of terms are unacceptable.

    +

    Also, keep in mind that documentation will be used for searching as well, so every page should contain all the keywords required to be properly ranked by search engines. Unfortunately, this requirement contradicts the simple-and-laconic principle; that's the way.

    Documentation Content Types

    1. Specification / Reference

    Any documentation starts with a formal functional description. This content type is the most inconvenient to use, but you must provide it. A reference is the hygienic minimum of the API documentation. If you don't have a doc that describes all methods, parameters, options, variable types, and their allowed values, then it's not an API but amateur dramatics.

    Today, a reference must be also a machine-readable specification, e.g. comply with some standard, for example, OpenAPI.

    -

    A specification must comprise not only formal descriptions but implicit agreements as well, such as the event generation order or unobvious side-effects of the API methods. Its most important applied value is advisory consulting: developers will refer to it to clarify unobvious situations.

    +

    The specification must comprise not only formal descriptions but implicit agreements as well, such as the event generation order or unobvious side-effects of the API methods. Its important applied value is advisory consulting: developers will refer to it to clarify unobvious situations.

    Importantly, formal specification is not documentation per se. The documentation is the words you write in the descriptions of each field and method. Without them, the specification might be used just for checking whether your namings are fine enough for developers to guess their meaning.

    Today, the method nomenclature descriptions are frequently additionally exposed as ready-to-use request collections or code fragments for Postman or analogous tools.

    2. Code Samples
    @@ -3916,23 +3921,22 @@ ProgramContext.dispatch = (action) => {
  • proper reactions to program errors that could happen;
  • detailed studies on advanced API functionality (with detailed examples).
-

As usual, a tutorial comprises a common section (basic terms and concepts, notation keys) and a set of sections regarding each functional domain exposed via the API.

-

Usually, tutorials contain a “Quick Start” (“Hello, world!”) section: the smallest possible code sample that would allow developers to build a small app atop the API. “Quick Starts” aim to cover two needs:

+

Usually, a tutorial comprises a common section (basic terms and concepts, notation keys) and a set of sections regarding each functional domain exposed via the API. Frequently, tutorials contain a “Quick Start” (“Hello, world!”) section: the smallest possible code sample that would allow developers to build a small app atop the API. “Quick Starts” aim to cover two needs:

  • to provide a default entry-point, the easiest to understand and the most useful text for those who heard about your API for the first time;
  • to engage developers, to make them touch the service by a mean of a real-world example.

Also, “Quick starts” are a good indicator of how exactly well did you do your homework of identifying the most important use cases and providing helper methods. If your Quick Start comprises more than ten lines of code, you have definitely done something wrong.

-
5. Frequently Asked Questions and a Knowledge Base
+
5. Frequently Asked Questions and Knowledge Bases

After you publish the API and start supporting users (see the previous chapter) you will also accumulate some knowledge of what questions are asked most frequently. If you can't easily integrate answers into the documentation, it's useful to compile a specific “Frequently Asked Questions” (aka FAQ) article. A FAQ article must meet the following criteria:

  • address the real questions (you might frequently find FAQs that were reflecting not users' needs, but the API owner's desire to repeat some important information once more; it's useless, or worse — annoying; perfect examples of this anti-pattern realization might be found on any bank or air company website);
  • both questions and answers must be formulated clearly and succinctly; it's acceptable (and even desirable) to provide links to corresponding reference and tutorial articles, but the answer itself can't be longer than a couple of paragraphs.
-

Also, FAQs are a convenient place to explicitly highlight the advantages of the API. In a question-answer form, you might demonstrably show how your API solves complex problems easily and handsomely. (Or at least, solves them generally unlike the competitors' products.)

+

Also, FAQs are a convenient place to explicitly highlight the advantages of the API. In a question-answer form, you might demonstrably show how your API solves complex problems easily and handsomely. (Or at least, solves them, unlike the competitors' products.)

If technical support conversations are public, it makes sense to store all the questions and answers as a separate service to form a knowledge base, e.g. a set of “real-life” questions and answers.

6. Offline Documentation
-

Though we live in the online world, an offline version of the documentation (in a form of a generated doc file) still might be useful — first of all, as a snapshot of the API valid for a specific date.

+

Though we live in the online world, an offline version of the documentation (in a form of a generated doc file) still might be useful — first of all, as a snapshot of the API specification valid for a specific date.

Content Duplication Problems

A significant problem that harms documentation clarity is API versioning: articles describing the same entity across different API versions are usually quite similar. Organizing convenient searching capability over such datasets is a problem for internal and external search engines as well. To tackle this problem ensure that:

    @@ -3953,7 +3957,7 @@ ProgramContext.dispatch = (action) => {

    Yes / No

    Chapter 31. The Testing Environment 

    If the operations executed via the API imply consequences for end users or partners (cost money, in particular) you must provide a test version of the API. In this testing API, real-world actions either don't happen at all (for instance, orders are created but nobody serves them) or are simulated by cheaper means (let's say, instead of sending an SMS to a user, an email is sent to the developer's mailbox).

    However, in many cases having a test version is not enough — like in our coffee-machine API example. If an order is created but not served, partners are not able to test the functionality of delivering the order or requesting a refund. To run the full cycle of testing, developers need the capability of pushing the order through stages, as this would happen in reality.

    -

    A direct solution to this problem is providing a full set of testing APIs and administrative interfaces. It means that developers will need to run a second application in parallel — the one you're giving to coffee shops so they might get and serve orders (and if there is a delivery functionality, the third app as well: the courier's one) — and make all these actions that coffee shop staff normally does. Obviously, that's not an ideal solution, because of several reasons:

    +

    A direct solution to this problem is providing test versions for a full set of APIs and administrative interfaces. It means that developers will be able to run a second application in parallel — the one you're giving to coffee shops so they might get and serve orders (and if there is a delivery functionality, the third app as well: the courier's one) — and make all these actions that coffee shop staff normally does. Obviously, that's not an ideal solution, because of several reasons:

    • developers of end user applications will need to additionally learn how coffee shop and courier apps work, which has nothing to do with the task they're solving;
    • you will need to invent and implement some matching algorithm: an order made through a test application must be assigned to a specific virtual courier; this actually means creating an isolated virtual “sandbox” (meaning — a full set of services) for each specific partner;
    • @@ -3965,25 +3969,24 @@ ProgramContext.dispatch = (action) => {

      Ideally, you should provide helper methods for any actions that are conducted by people in the production environment. It makes sense to ship this meta-API complete with ready-to-use scripts or request collections that show the correct API call orders for standard scenarios.

      The disadvantage of this approach is that client developers still need to know how the “flip side” of the system works, though in simplified terms.

      2. The Simulator of Pre-Defined Scenarios
      -

      The alternative to providing the testing environment API is simulating the working scenarios. In this case, the testing environment takes control over “underwater” parts of the system and “plays” all external agents' actions. In our coffee example, that means that, after the order is submitted, the system will simulate all the preparation steps and then the delivery of the beverage to the customer.

      +

      The alternative to providing the testing environment API is simulating the working scenarios. In this case, the testing environment takes control over “underwater” parts of the system and “plays out” all external agents' actions. In our coffee example, that means that, after the order is submitted, the system will simulate all the preparation steps and then the delivery of the beverage to the customer.

      The advantage of this approach is that it demonstrates vividly how the system works according to the API vendor design plans, e.g. in which sequence the events are generated, and which stages the order passes through. It also reduces the chance of making mistakes in testing scripts, as the API vendor guarantees the actions will be executed in the correct order with the right parameters.

      The main disadvantage is the necessity to create a separate scenario for each unhappy path (effectively, for every possible error), and give developers the capability of denoting which scenario they want to run. (For example, like that: if there is a pre-agreed comment to the order, the system will simulate a specific error, and developers will be able to write and debug the code that deals with the error.)

      The Automation of Testing

      Your final goal in implementing testing APIs, regardless of which option you choose, is allowing partners to automate the QA process for their products. The testing environment should be developed with this purpose in mind; for example, if an end user might be brought to a 3-D Secure page to pay for the order, the testing environment API must provide some way of simulating the successful (or not) passing of this step. Also, in both variants, it's possible (and desirable) to allow running the scenarios in a fast-forward manner that will allow making auto-testing much faster than manual testing.

      -

      Of course, not every partner will be able to employ this possibility (which also means that a “manual” way of testing usage scenarios must also be supported alongside the programmatical one) simply because not every business might afford to hire a QA automation engineer. Nevertheless, the ability to write such auto-tests is your API's huge competitive advantage from a technically advanced partner's point of view.

      Chapter 32. Managing expectations 

      +

      Of course, not every partner will be able to employ this possibility (which also means that a “manual” way of testing usage scenarios must always be supported alongside the programmatical one) simply because not every business might afford to hire a QA automation engineer. Nevertheless, the ability to write such auto-tests is your API's huge competitive advantage from a technically advanced partner's point of view.

      Chapter 32. Managing expectations 

      Finally, the last aspect we would like to shed the light on is managing partners' expectations regarding the further development of the API. If we talk about consumer qualities, APIs differ little from other B2B software products: in both cases, you need to form some understanding of SLA conditions, available features, interface responsiveness and other characteristics that are important for clients. Still, APIs have their specificities

      Versioning and Application Lifecycle

      Ideally, the API once published should live eternally; but as we all are reasonable people, we do understand it's impossible in the real life. Even if we continue supporting older versions, they will still become outdated eventually, and partners will need to rewrite the code to use newer functionality.

      -

      The author of this book formulates the rule of issuing new major API versions like this: the period of time after which partners will need to rewrite the code should coincide with the application lifespan in the subject area. Any program will once become obsolete and will be rewritten; and if during this re-developing partners need to also switch to a newer API version, it will be met with some degree of understanding. Of course, in different subject areas, this timespan differs, depending on the evolution rate of the underlying platform.

      -

      Apart from updating major versions, sooner or later you will face issues with accessing some outdated minor versions as well. As we mentioned in the “On the Waterline of the Iceberg” chapter, even fixing bugs might eventually lead to breaking some integrations, and that naturally leads us to the necessity of keeping older minor versions of the API until the partner resolves the problem.

      -

      In this aspect, integrating with large companies that have a dedicated software engineering department differs dramatically from providing a solution to individual amateur programmers: from one side, the former are much more likely to find undocumented features and unfixed bugs in your code; on the other side, because of the internal bureaucracy, fixing the related issues might easily take months, save not years. The common recommendation there is to maintain old minor API versions for a period of time long enough for the most dilatory partner to switch no the newest version.

      +

      The author of this book formulates the rule of issuing new major API versions like this: the period of time after which partners will need to rewrite the code should coincide with the application lifespan in the subject area (see “The Backwards Compatibility Problem Statement” chapter). Apart from updating major versions, sooner or later you will face issues with accessing some outdated minor versions as well. As we mentioned in the “On the Waterline of the Iceberg” chapter, even fixing bugs might eventually lead to breaking some integrations, and that naturally leads us to the necessity of keeping older minor versions of the API until the partner resolves the problem.

      +

      In this aspect, integrating with large companies that have a dedicated software engineering department differs dramatically from providing a solution to individual amateur programmers: on one hand, the former are much more likely to find undocumented features and unfixed bugs in your code; on the other hand, because of the internal bureaucracy, fixing the related issues might easily take months, save not years. The common recommendation there is to maintain old minor API versions for a period of time long enough for the most dilatory partner to switch no the newest version.

      Supporting Platforms

      Another aspect crucial to interacting with large integrators is supporting a zoo of platforms (browsers, programming languages, protocols, operating systems) and their versions. As usual, big companies have their own policies on which platforms they support, and these policies might sometimes contradict common sense. (Let's say, it's rather a time to abandon TLS 1.2, but many integrators continue working through this protocol, or even the earlier ones.)

      -

      Formally speaking, ceasing support of a platform is a backwards-incompatible change, and might lead to breaking some integration for some end users. So it's highly important to have clearly formulated policies on which platforms are supported based on which criteria. In the case of mass public APIs, that's usually simple (like, API vendor promises to support platforms that have more than N% penetration, or, even easier, just last M versions of a platform); in the case of commercial APIs, it's always a bargain based on the estimations, how much will non-supporting a specific platform would cost to a company. And of course, the outcome of the bargain must be stated in the contracts — what exactly you're promising to support during which period of time.

      +

      Formally speaking, ceasing support of a platform is a backwards-incompatible change, and might lead to breaking some integration for some end users. So it's highly important to have clearly formulated policies regarding which platforms are supported based on which criteria. In the case of mass public APIs, that's usually simple (like, API vendor promises to support platforms that have more than N% penetration, or, even easier, just last M versions of a platform); in the case of commercial APIs, it's always a bargain based on the estimations, how much will non-supporting a specific platform would cost to a company. And of course, the outcome of the bargain must be stated in the contracts — what exactly you're promising to support during which period of time.

      Moving Forward

      Finally, apart from those specific issues, your customers must be caring about more general questions: could they trust you? Could they rely on your API evolving, absorbing modern trends, or will they eventually find the integration with your API on the scrapyard of history? Let's be honest: given all the uncertainties of the API product vision, we are very much interested in the answers as well. Even the Roman viaduct, though remaining backwards-compatible for two thousand years, has been a very archaic and non-reliable way of solving customers' problems for quite a long time.

      You might work with these customer expectations by publishing roadmaps. It's quite common that many companies avoid publicly announcing their concrete plans (for a reason, of course). Nevertheless, in the case of APIs, we strongly recommend providing the roadmaps, even if they are tentative and lack precise dates — especially if we talk about deprecating some functionality. Announcing these promises (given the company keeps them, of course) is a very important competitive advantage to every kind of consumer.

      -

      With this, we would like to conclude this book. We hope that the principles and the concepts we have outlined will help you in creating APIs that fit all the developer', business', and end user's needs, and in expanding them (while maintaining the backwards compatibility) for the next two thousand years (or maybe more).