Gumroad perma ID usage

Gumroad’s perma IDs and their use in the API

As you might know, ninkik uses Gumroad as the primary payment platform. To keep everything up-to-date, we are using Gumroad’s API to synchronize products defined in Gumroad with the custom defined products in ninkik.

While building the synchronization feature, we stumbled upon some quirks when dealing with their perma ID system.

Perma IDs? This sounds simple.

As soon as you create a product inside Gumroad, Gumroad generates a unique perma link like, where WzxlQ is the perma ID.

You can change the perma ID at any point in time to something more meaning full like my-custom-perma-id-old and my-custom-perma-id-new. To our knowledge, there is no limit how often you change the perma ID. The only restriction is that same perma ID can understandably only be used one time at the time in Gumroad, due to their uniqueness. From a relational poiont of view you have a 1-{1,2} relationship between a Gumroad product and their perma IDs. The history of perma IDs is not tracked.

Verification of licenses

When using Gumroad’s /licenses/verify API, you have to provide a product_permalink parameter. The parameter should be named product_perma_id as only the ID must be provided, but this is another story.
The product_permalink can bei either WzxlQ or my-custom-perma-id-new. Any perma ID you have previously chosen, like my-custom-perma-id-old, is not valid.

Depending upon your use case of the API, you have to synchronize all of your products periodically to always get the latest perma ID.

License verification response

After doing a license verification request, you receive either a negative response ("success": false) or a summary of the licensed product. If your product has no custom perma ID, the fields

  • permalink (containing only the perma ID WzxlQ)
  • and product_permalink (containing the complete URL)

are available.

If you have set a custom perma ID, the fields permalink and product_permalink are missing. Instead, the fields

  • custom_permalink (containing the latest perma ID my-custom-perma-id-new)
  • short_url (containing the complete URL)

are available.

Response from the products endpoint

When using Gumroad’s /products API endpoint, you are also not be able to retrieve the original perma ID:

JSON fieldWithout custom perma IDWith custom perma ID
custom_permalinknullcustom perma ID (my-custom-perma-id-new)
short_url perma URL (
/products API response

Response from the sales endpoint

You can use the /sales endpoint to retrieve the original perma ID of a product’s sale. For each sale, only the field product_permalink is set, containing only the original perma ID and not any custom perma ID.

That being said, there is no way to retrieve the original perma ID if no sales has been made (which might not be so bad).

Best practices

You should not use Gumroad’s perma IDs as a external primary key attribute in your application. The different handling (and naming) of the attributes makes it complicated to write a deserializer.

  1. Use Gumroad’s product_id fields as a external primary key.
  2. For the Gumroad product in your application, have the following two nullable fields perma_id and custom_perma_id.
  3. Synchronize the Gumroad products to your application periodically. Depending upon the available fields f Gumarod’s API responses, set the perma_id or custom_perma_id accordingly.
  4. When doing a license verification, use either the perma_id or custom_perma_id as parameter.

Our proposal to improve Gumroad’s API handling of perma IDs

As you might have already guessed it, there are some suggestions we’d like to make:

  1. Each API response should contain the fields perma_id with the original perma ID (not a URL but only the ID) and custom_perma_id (nullable, not a URL but only the ID).
  2. Mark the different other variants as deprecated in the documentation.
  3. The /licenses/verify should have a parameter product_id which can be used instead of the perma ID.

Summing it up

Even if Gumroad’s perma IDs looks like a simple topic, it shows how complexity evolves over time.