We at Gikken recently acquired Tokens, an app for developers, that allows you to easily generate promo codes, share them as a link, and track if they were redeemed. It also presents the user with a very straigforward way of redeeming a promo code, instead of you giving him instructions.
It uses App Store Connect "API" to do what it does.
Unfortunately, there is no public App Store Connect API.
Fortunately, the App Store Connect is a single page web app. This makes it a terrible service to use, but a very easy one to use APIs from.
All the stuff that is happening on ASC is done by sending HTTP requests with JSON as an info media. That's literally the best thing Apple could do if they wanted someone to use ASC APIs in other applications 😃.
So, the backstory:
You may know fastlane, a tool that makes a lot of stuff easier for you as an iOS developer. Some of its parts communicate with the App Store Connect, so there's no need to sniff all the requests and figure out what headers and parameters are important and which are not. The fastlane folks did all this for us. Matthias Gansrigler then used their code to write the ESSAppStoreConnectAPI, which is used in Tokens now.
The problem is: we're writing a new version of Tokens from scratch, and we're doing it in Swift. I am one of the
lucky ones that have never seen Obj-C development, as I started my Apple dev endeavours in 2014, a couple days after Swift was released.
If I just fixed a couple things in the current library and we continued using it – I would most definitely not come back to improve it or add some features. That would be hard to justify given all that Obj-C bracket-tangledness and type-unsafety.
The decision was to rewrite the lib in Swift completely, which I successfully did.
It's not hard to rewrite something from Obj-C to Swift, since you're still using mostly the same APIs and classes, just named a little differently. What was hard is to guess the types of some objects, so I had to study the original Apple JSONs for that.
What I also did differently is I used
structs for the data models instead of
NSDictionaries. I also ended up embedding SwiftyJSON to work with JSON much more easily than it's done with the native Apple instruments. I was resisting to do so for 80% of the process, but then I finally gave up 🥳. I don't know how come that SwiftyJSON is not a part of the language yet.
Here's the lib itself: GKAppStoreConnectApi
How to use it:
The lib is a singleton, so you don't have to initialize it, you just call the methods on
The first thing that needs to be done is you have to log in the user. There's
loginWith(username:password:) for that. It will either immediately log the user in, or it will tell you that 2FA is active and your user needs to give you the code. You can also use the
info object in the completion handler to see all the available 2FA options and give the user a choice. If you decide to do so – there's a
After you've got the code from te user – call
finish2FAWith(code:phoneID:) it will automatically know if the code was sent to a trusted device or as an SMS and call the right endpoint, which are different for some reason. Now we have that sweet login cookie.
After we've got the cookie – the library will request the user session from the ASC, which contains all the info about the users teams, it also immediately downloads the apps for the current team.
currentTeam and decide if it's the right one. Nevermind it if the user has only one team. If it's not the right one – go ahead and use the
switchToTeamWith(teamID:) method, and
getTeams() will help you list those.
Now that the team part is settled – we can access the apps via
getApps(). If the app is paid and you need a promo code for it – use
requestPromoCodesForAppWith(appID:versionID:quantity:contractFilename:). You can find the
versionID and the
contractFilename parameters in the app object you got from
It takes some time to get the codes, so you're better off presenting an activity indicator while it loads.
Most probably, your app is free and it offers an IAP of some sort, cuz it's 2020, right? You will have to request a list of IAPs with
iapsForAppWith(appId:), and with that info you can use the
requestIapPromoCodesFor(iapID:appID: quantity:). Be patient, it's not instant too. Still much faster than the actual App Store Connect though 😏.
Now, the question is, what're you gonna do with all those codes?
We, for example, are using those for Tokens 2, to make not only code creating, but also redeeming, a breeze. It's in active development now. If you developer iOS or Mac apps (or both), wait no longer and sign up for a beta now!