I dislike Stripe's API. There are parts of it that just make no sense.
Say, you want to set a billing date for that fancy subscription. Yeah, just set a trial date until the billing date you want. Oh, and don't forget to charge a prorated difference (by hand, with charges)!
Want to upgrade that subscription? Yeah, cancel that subscription and start a new one. Oh, and don't forget to set that trial again!
Want to cancel that subscription but not until their next billing date? Hahaha, yeah no. You need to cancel now through Stripe and set up a process to cancel on your side. (Not the biggest complaint, but really. If I am having Stripe manage my subscriptions, they should do it all)
And I am sure there are many other details which would also drive me mad.
With all of that said, I think Stripe's API is definitely one of the better ones since my complaints are more functionality / feature requests than complaints about how it is set up.
Although it’s kind of proving your point that the API could be easier to use/better documented, here are some simpler ways to do what you’re looking for:
That said, agreed overall that our subscriptions support needs some love. We're starting to spend more time on exactly this, so would love any feedback you (or anyone else reading) are willing to share. I'm eduardo@stripe.com.
Thanks Eduardo. I've interacted with you (I think) a couple times and really appreciate the effort you all put into customer outreach. It is appreciated. I will have my team jot down thoughts on subscription functionality and send it over.
I agree. Their subscription functionality is half-baked. We're 2 years into using Stripe for subscription management and it's such a hassle to move anywhere else that we keep hobbling along with it.
My advice when starting a SaaS company: think through your subscription software early on, before it's a headache to even think about migrating away.
Also, the provided Java client is garbage (you need to put all the arguments into an untyped hashmap that corresponds to the JSON, WTF?).
And why are there separate clients for Java and Android, which both use the same namespace differently?
And why do I need to set the API key as a global for the general Java client, while the Android client (sensibly) lets me give it as a constructor argument?
I recently used Laravel Spark [ https://spark.laravel.com/ ] to manage all the subscriptions and I really love it!
Before I had to do it all by myself and it was a nightmare and so much time taken away to develop the real app.
I highly recomment it for any SaaS product. It gives you a huge jumpstart and you can concentrate on developing just your app.
Btw, it supports both Stripe and Braintree.
I did that too, mostly because I am splitting transactions to connected accounts and subscriptions don't play nicely with that functionality, according to the docs.
So you want to set a billing date and then charge a pro-rated amount that first month?
And what do you mean "upgrade"? You can move from one plan to the next and charges are pro-rated automatically for you.
I, too, loath the amount of time we've spent on subscription/billing but I'm just surprised that none of the issues you've listed are really causing any pain for us.
It seems like the API is way too complex to do certain operations. Especially some very common use cases: for example, how to apply discount for next year for customers who already have subscription (we wanted to emulate how Comcast always gives you discount if you want cancel and took us weeks to make that working ...). I think they do want to fix all these issues but API is not designed to be easily expandable.
It's actually very hard to find a decent REST API :(
My points here are the following:
1. Think very very hard about how people will use your API <-- this is critical. This also includes operational characteristics of your API (performances, how often it is going to be called, optimization, etc.)
2. Make API easily expendable. Especially relationships between models. Sometimes, it is ok (or even better) just to organize it as "SQL wrapper". Like SOQL by Salesforce - but that again depends on number 1.
Jeez, glad I'm not the only who feels Stripe's API is basically the golden standard when it comes to a properly implemented REST API and documentation.
-1 for Stripe. The API is designed without any thought how the use cases need to use it. Leaks the JSON structure of the document to the client. This breaks your code when they change the JSON structure.
I'm not sure what you mean about changing the JSON structure; the Stripe API is versioned and you have to opt-in to any updates, including breaking changes like removing or renaming keys in the response.
nit picking devil's advocate: not all of the API is documented. There are some features that exists, but you have to know about. Granted, this is intentional. e.g.: "billing_cycle_anchor" in the subscription API.
Came here to recommend Stormpath, too. I don't actually use their API but the docs are amazing and some of their presentations on REST API design are phenomenal.
The key to a great API? Have the developer / designer of the API write the first set of client applications before the API is published externally. I have integrated with many dozens of APIs over the years and it is immediately obvious (and unfortunately too common) when the designer of the API has never been in the seat of the client developer.
Sorry for not pointing to specific examples, but things I really love to see in an API:
- Fully qualified URLs in all links (makes navigating and discovery in Postman a breeze).
- Ability to expand resources represented by links (even deeply nested resources) so I can get exactly what I need in a single request.
- The ability to specify what parts of the response resource to include / exclude, allowing me to slim the response to exactly what I need. More important in clients running on mobile devices where slender responses make a noticeable performance difference.
- The exact same URLs (including hostnames) for the test and production API, the difference between the environments being determined by the credentials used in the request. This greatly simplifies code in the client test and production environments.
- Security schemes that allow me to write serverless client applications (OAuth 2 implicit grant). This certainly requires more work by the API developer, but makes it possible to crank out all sorts of useful tools quickly, and massively reduces client IT overhead. This may not be appropriate for all APIs, but could be used a lot more often than it is.
- Along with the above, support for CORS so we don't have to mess around with JSONP and other hacks in the browser.
- If you make me eat your timezone, please please make it UTC. But spend a little extra effort and allow me to pass a timezone in, either as an account settings and/or request parameter (and a simple offset isn't good enough - support actual timezones so daylight saving is handled). It can be incredibly hard to analyze data in responses when you're constantly having to translate the time to your own to give proper context. Timezone support isn't fun but libraries make it pretty easy. This is more important in APIs that provide lots of transactional data.
- Let me attach meta data to resources - it doesn't even have to be a lot. Sometimes allowing me to slip in a handful of bytes removes the need for an entire database on my side.
- Be painfully explicit in error responses. State the obvious, especially in errors that are likely to occur at the beginning of integration such as issues with authentication, content types, payload structure, etc.
> - Let me attach meta data to resources - it doesn't even have to be a lot. Sometimes allowing me to slip in a handful of bytes removes the need for an entire database on my side.
So much +1's for this. Even better if I can query for it.
Yeah. And at very least budget some API dev time to respond as the client design unfolds. A static API, with an frontend app in discovery phase is a sad state of affairs.
I like where Plaid is going but it bothered me that they are coy about their pricing.
Typically when a company refuses to say their price or says "Contact Us", that means "Prepare your wallets".
With that said, very economical. I think it was something like $0.10 per account you add. I am looking forward to Plaid expanding what banks are offered since currently they only work with 10 or so (although if they pick you, they give you access to a few thousand more. Not sure the criteria)
Hi Madeline - Charley from the Plaid growth team here. Totally get where you're coming from in regards to pricing, we're working on a bunch of improvements to the site, of which pricing is at the top of my list to get on there! So that will be on there soon :)
If you have any other questions, feel free to reach me directly at charley@plaid
I came here to say this. I recently built a pretty tight integration between Trello and our app, and using the API was quite pleasant. The documentation isn't stellar (it has examples for requests, but not responses, s you need to use trial and error), but everything is standardized, so once you figure out the logic, you're golden.
I actually found Trello's API to be one of the worst most non-compliant restful API's I've seen. Nothing about it is restful with the extra actions they have on resources. It's hard to follow. The docs are sub-par too.
I interviewed with Trello and one part of my interview was building a super simple app in an hour using their API. As far as APIs go, and never having used Trello's API before, I found it to be fairly intuitive and documented well enough for me to skim quickly to needed information. I completed the task with time to spare, and only choked a bit on the authentication. If you don't like Trello's API, give the AWS API a shot!
It's ok but once you start implementing things it gets a bit hairy. Mostly because folders aren't really folders in their API, even though they are in every app that uses them. And their search API to find folders is flaky at best, as it's a consequence of the above problem.
To summarize: send a 202 for the initial request, redirecting to a job URL. The client polls on the job URL, which returns 200 with progress information until it's done, when it returns a 303 redirecting to the final output.
One particular problem spot is that many http libraries automatically follow the 303 redirect, and some even follow the 202 redirect.
I definitely think we would have been better off just putting status and final location information as JSON attributes in the body rather than putting it in HTTP response codes and Location headers. Non-standard, but much less confusing for our customers.
And all computations can be modeled as Universal Turing Machines at some level. That doesn't mean it's the most useful level at which to analyze the semantics of what you are trying to accomplish.
The short answer is that there is really no good general purpose way to deal with asynchronous communication in a "restful" HTTP API. All solutions have major drawbacks. This is one of the biggest shortfalls of rest/http in my experience. People tend to switch to other protocols to address these use cases (this is a common reason for adopting message bus infrastructure like Kafka as part of a SOA).
DigitalOcean's API does this in quite a few spots [1] - it calls the async jobs "actions", but they signal completion of jobs performed on base objects.
I think it could use improvement. Look at https://api.slack.com/methods/chat.postMessage and explain how "as_user" makes any sense. And it gets more convoluted depending on other parameters used (IM channels, etc.)
Also, why can't I use a secret key with my basic postMessage script? I have to navigate OAuth2 just to make a post? Argh the pain!
Well done. I opened your link, expecting more banal hand waving dogma. Instead, I found myself nodding agreement with most items in your list. Thank you.
My employer (Apigee) makes a good introductory ebook on this topic. Be forewarned this is a huge topic with many (strong) opinions on what 'good' REST actually is.
It used to always be cited as an example of a good REST API see this same question from 7 years ago and you'll see Twilio is top recommended https://news.ycombinator.com/item?id=867972
Oh and still is today because it's a good API - timeless
I've been using flask-restless to good effect. Then you don't build your own api at all, you just generate it based on your database model. You get urls like /persons/23/edit, /persons/77/delete and so on by free. There is also Django restless which is pretty good too.
HATEOAS is a pain in the ass to implement, people know what it means, they just don't bother implementing it. It's often not a necessary feature for an API. HATEOAS is even more painful when using JSON, a format that doesn't really support metadatas ( a link is meta compared to a ressource ) and very little clients are built with HATEOAS in mind.
The REST paper has good ideas, and people are picking and choosing what they want. There is no REST specification that makes HATEOAS mandatory. Maybe Roy Fielding should have written one on top of HTTP to make it clear what it is about instead of writing an dissertation.
How do you represent a link semantically? 100 businesses will have 100 different answers. That's why, by the way, HTML was so ingenious. HTML tags ARE semantic. If Roy came with a core set of tags describing things then people would know how to write basic HATEOAS APIs.
So don't blame the people, blame the absence of a clear specification(and no, the REST paper is not a spec, a spec is normative).
All this shouldn't matter as long as every IS documented. HATEOAS can't replace a good documentation. Today, for most developers REST is about urls, verbs and caching + a few other headers, nothing more.
Many do know. But they just choose one step lower lever on Richardson maturity model as more pragmatic. Yes, according to Fielding that level cannot be called RESTfull, oh well…
PostgREST is a standalone web server that turns your postgresql database directly into a RESTful API.
The REST API is designed intuitively, just as one would expect.
I've been using it a lot for prototyping and internal applications. Now with the help of native row level security from postgres, it would become also a good choice for production. Or just wrap it behind your gateway.
Odata is à standardized rest use case for generaal purpose data access, so client tools can use it out of the box. Something like sql but over http. Some tools that provide odata support: tableau, tibco spotfire, linqpad, excel.
Excel is a nice example, you can have a sheet with data pulled in over odata from any app that supports odata.
OData is more or less SQL over HTTP. You get a rich toolbox for selection, projection and transformation of datasets exposed as an OData source (think EBay listings and SQL Server tables and reports), along with the remaining letters of CRUD.
It depends on the problem - if the particular interface is semantically suitable for REST, then there won't be any overhead and REST will just be a useful convention on how exactly you should represent it; and on the other hand if that particular interface needs are not suitable for REST then you probably should implement it with RPC, message queues or whatever other option better suits the problem instead of trying to mangle it into REST paradigm.
Maybe. It adds a whole layer of complexity, but it might be worth it. Depends on your team's structure and relevant experience, and on the details of the project.
One nitpick: it always feel weird to me to have an error (or any other object) where the attributes are named like this:
{
"errorCode": "E0000001",
"errorSummary": "Api validation failed",
"errorLink": "E0000001",
"errorId": "oaeHfmOAx1iRLa0H10DeMz5fQ",
"errorCauses": [
{
"errorSummary": "login: An object with this field already exists in the current organization"
}
]
}
The Sun Cloud API [1] was specifically designed to adhere to REST as close as possible, including HATEOAS. Here's some background from Tim Bray [2], who worked on this API when he was at Sun [3].
We have been using Swagger and developed a REST API library [1] in Java that automatically generates Swagger specification for your API using static analysis. We can also automatically generate client libraries (https://github.com/buremba/rakam-client) and API documentation (http://api.rakam.io/) from Swagger specification. Currently, the library lacks documentation but it can at least give you the idea.
The latest version of Swagger Codegen (https://github.com/swagger-api/swagger-codegen) also automatically generates documentation (markdown) for API clients/libraries, e.g. installation, getting start, doc for API endpoints and models.
Nice! Instead of generating Markdown files, you could also generate full HTML documentation similar to Slate. The generated Markdown files can be used in Slate since the format seems to be similar. Actually I opened an issue in swagger-codegen repo (https://github.com/swagger-api/swagger-codegen/issues/1387) and we talked about it. The reason that I created a separate project is that the the example usage section and the format didn't seem to be implemented as language in swagger-codegen.
I notice that you put all the clients (C#, Java, Ruby, PHP, etc) under the same Github project.
I would suggest you to create separate Github repo for API clients in different languages so that developers can install the PHP, Python, Ruby, etc API clients directly from the Github repo.
You can leverage "git_push.sh" to push the auto-generated SDKs (with doc, sample code) to Github.
Are we just talking about API documentation? Stripe's the obvious go-to for that, but for big business stuff I was pleasantly surprised with HubSpot's API and documentation. Their own UI uses the API, which means debugging a lot easier I think: http://developers.hubspot.com/docs/overview
EXCEPT for the fact they decided to use .NET date formats throughout their API rather than the more traditional ISO date formats. (I do like that they sheepishly apologised for this in their API docs).
Also, they are usually a few months behind releasing API coverage of new features and modules.
Also, it is a bit fiddly having to specify a 'scope' parameter when authenticating yourself for the API otherwise you won't be able to access certain data.
Lastly, I don't like the way there is almost a separate API for the AU and US version of Payroll. I get that they are fairly different beasts, and that they are actually third party systems that have been 'integrated' in, but I wish they had more commonality.
Nope. Try adding a Client Group with no clients via the API - you can't. Xero have admitted that it's a problem, and basically won't commit to ever fixing it. There are another couple of examples relating to problems with the Xero API that don't come to mind right now, but indeed there are problems.
Not a comment on the API itself, but I like how Stackoverflow/Stackexchange has interactive documentation, allowing you to fill in prompts and have it create the request for you and show the live results.
SurveyMonkey has a very good setup - pretty much anything you can do with their web app, you can also do via the API. https://developer.surveymonkey.com
"URLs should never be constructed by an API client. Instead, the client should only follow links that are generated by the API itself."
I really hate this notion. It makes jumping to page 100 of a 345 page result set impossible. You would literally have to follow 100 pages, or have some ridiculously long index with 345 separate links.
I believe that it should be possible for an API to document a URL formula, and rely on the API client to follow that formula to generate a URL.
That's where things get sticky, though, because as far as I know, there's no good standard defined for how an API can document a dynamic URL formula that is programmatically discoverable.
I'm not sure whether it's a "good" standard, but that doc indirectly links to "URI Templates" [0] It isn't clear to me how that works on the client side however. Can we just assume that clients know how to construct a URI using a template? I guess we can, since it's no more difficult than using the specific API knowledge required to "jump to page 100" as you want to do.
Your documentation is great! You've got straightforward authentication, prominent curl examples, expected responses, clear-cut explanations of expected inputs... I think your API looks fun and easy to use! I don't send physical mail, but if I did and tried your API, I would probably get in trouble for mail-bombing hate mail to my elected officials.
Hey, wait a minute! Those examples are using test credentials... Your API responds to those curl calls with real output, and the output matches what your documentation says it should be. Okay, that is awesome! Also when I force myself to get rate-limited, my requests fail gracefully with a "429 Too Many Requests" and a descriptive error, which is refreshing. Nice API!
JSON API seems overly verbose to me. It feels like like a direct descendant of the SOAP / WSDL era -- or maybe I'm just scarred from having written and consumed SOAP webservices.
Have you actually implemented something following this spec? My experience is that it's somewhat okay-defined for consuming data, but the spec itself is wildly incomplete in the other direction. Looking at the repo and discussion forum, the maintainers are inactive, with tons of open questions unanswered.
I implemented two APIs with it, mostly read oriented to be honest. The biggest problem we faced is the lack of maturity of Android and iOS SDKs for it.
No; nor does it need the overhead of having to navigate through several lists to get to the desired URI when it could infer the full URI from the very beginning.
You are free to type in any URI you like. In fact, a REST client can save links (bookmarks) or cache payloads that contain these links / forms (templates). But don't expect the server to not change things. So being able to navigate is a form of resilience. For me, thats worth to have with what you call "overhead". I call it a sane tradeoff.
Inferring the URI rather than pointlessly downloading ten end points to walk the full options list every time, also seems sane; the former doesn't seem like "doing it wrong".
Caching doesn't solve the problem of "what if I want to look up the travel time between this other city and this other city via this other means".
What do you mean to look up travel times? I'd provide a resource that you can POST to and the server computes the travel time. There is no caching useful here. But way to create the request (like a form) can be provided by a document. And this document can be cached by a client.
The request will be idempotent so it shouldn't be a POST. But if it's a GET, then you're telling me I shouldn't tell the client where to put the start and end city in a request URI?
Right, which means that if I followed the REST principle (clients don't construct URIs), then every request must make an extra, unnecessary round trip for every parameter. Which sounds quite pointless.
Yes sounds like it. Plus if the option is a geo coordinate then it's impractical to list them all. I don't see the problem with meta data or assumed knowledge.
In case some don't take this seriously: it is true. Rails does pretty good job in this recard. It is not HATEOAS, bet otherwise it pretty solid and follows best practices quite well.
https://stripe.com/docs/api