Maximum suffering - minimal effort
This guide and the descriptions below are fictitious. No identification with actual APIs (living or dead) is intended or should be inferred - especially not seller, vendor, marketplace, or advertising APIs from companies named after notable rainforests.
1. Keep your documentation accuracy as close to 66.6% as possible
Obviously 66.6% looks rather insidious, but that’s purely coincidental.
Found through extensive trial and error, 66.6% is the “golden ratio” for API documentation. Your docs have to be accurate enough to keep API users referencing them, but inaccurate enough to cause untold suffering.
The most fun part of this is redirecting users to the docs when they inevitably open support tickets about everything else in this guide.
2. Use completely different ID’s for your UI and your API
Using different ID’s is only half the battle; you need to make sure there’s literally no way for API users to map between the IDs in the UI and the IDs in the API.
Make integrators try to guess which resource is which based on fields that aren’t unique in any way. That’s half the fun.
Bonus points if you have a third layer of completely separate object IDs for internal use.
3. Rotate HTTP codes and messages for the exact same errors
API integrators get complacent if you leave their error handling intact for too long.
As a rule, make your errors as vague as possible, but when you can’t avoid specificity, make it a point to reword and reclassify errors at regular (but not too regular) intervals.
You can rephrase “this region is not supported” in many ways - “support is not available in this region”, “support for this region is not yet implemented”, “this operation is not available in this marketplace”, etc.
And don’t forget to change your response codes. Change some
429 Too Many Requests to
401 Unauthorized’s. Change some
401 Unauthorized’s to
403 Forbidden’s. Hell, change some
400 Bad Request’s to
200 OK’s - you get the idea.
The important thing is to make sure your errors change all the time. Let loose and don’t be afraid to experiment!
4. Use PATCH and PUT interchangeably
HTTP verbs are more what we’d call “guidelines”, after all. Use
PUT to mean
PATCH on 70-90% of endpoints. While tempting, don’t make the mistake of doing it too consistently - your users will figure it out.
For the 30-10% of the time when you really mean
PUT, it’s quite fun to require fields that the user has no way of retrieving - never return all the required data in your
If API users ask about these mystery fields, pretend to miss the point and lecture them about how
PUT requests work. Direct them to the documentation.
5. Reuse old ID’s for new objects - uniqueness can’t compete with frugality
When API objects can finally be retired, it would be wasteful to retire the unique identifier with them. With rising support for renewables across virtually all demographics, the only thing better than a unique ID is a recycled ID.
Sustainable practices and invalidating countless amounts of user data at the same time? What’s not to love?
Like with #2, it’s critical to ensure that API users have no mechanism to determine which ID maps to which object. It’s pointless to invalidate swaths of data when your users can simply “undo it” by remapping millions and millions of foreign keys.
6. Consistency is the enemy of curiosity
In a vacuum, different teams will naturally produce very different APIs. Inertia is on your side - the hard part is maintaining that vacuum.
The sad truth is - many engineers will naturally want to provide a consistent experience for users. The best defence is to ensure that your devs have no concept of what ‘consistent’ would even look like.
Block teams off from existing work and documention. Cross-team coordination is completely out. If you find your team building consistent APIs - even accidentally, fabricate “user feedback” to guide them in a different direction.
7. Throttling and rate limits are best communicated by choosing error responses at random
More and more, API statistics are showing a sharp drop in API usage immediately following HTTP
429 Too Many Requests responses. This kind of user disloyalty will not reflect well on the team when placed in the quarterly powerpoint presentation.
How do you keep your users sending requests when you’re throttling them? Simple - you make sure they have no idea they’re being throttled.
429 Too Many Requests responses just often enough to make API users think they can rely on it. Now rotate in
400 Bad Request,
500 Internal Service Error,
502 Bad Gateway,
504 Gateway Timeout - all seemingly at random.
As a bonus, you can place the user authentication tokens in the error response body. This way, API consumers who save unexpected errors might accidentally log the auth tokens in plaintext.
Ignore any support tickets that suggest exposing credentials in response bodies may be inadvisable. Direct them to the documentation.
Honorable Mention: No incremental data ingestion - no pagination without missing rows
This one is easy:
- don’t sort by creation time
- don’t allow users to specify sort order
This works best for data that’s constantly having rows inserted. API users grab page 1 - and before they’ve grabbed page 2, you insert random rows that land in page 1. Now the hapless integrator will have to deduplicate the page 1 rows that come in again on page 2.
And the best part - if they ever want the new rows they missed - they have to walk through every page yet again.