Skip to content

🧾 Customers API & Management  #4543

@frankie567

Description

@frankie567

This is the next big milestone in Polar's development πŸ”οΈ

Polar aims to empower creators by building a seamless, intuitive platform that simplifies the journey of selling digital products and delivering exceptional customer experiences.

To achieve this, we want to overhaul the way creators manage their customers, so they can finely view their data and their associated orders, subscriptions and benefits.

Goal

We want to expose a unified API and tools to manage customers at organization level including:

  • Create, update and view customers from the API/dashboard
  • View a customer's orders and subscriptions
  • View and manage a customer's benefits, with the ability to manually grant or revoke them
  • Create customer's session/token so a customer can retrieve their benefit and manage their orders without creating a Polar user's account

Current state

In the current architecture, every customer is a User on Polar, uniquely identified by email, on which we link orders, subscriptions and benefit grants:

flowchart TD
    U[User]
    ORG[Organization]
    O[Order]
    S[Subscription]
    BG[BenefitGrant]
    B[Benefit]
    O --> U
    S --> U
    BG --> U
    BG --> B
    B --> ORG
    O --> ORG
    S --> ORG
Loading

The problem with this approach is that an Organization interacts directly with the global User object, which prevents features like creation/update of customers. Typically, if we want to introduce features like custom data for customers, it's very hard to do it with only the User level.

It also causes some UX issues, where the customer buys something and then needs to login to Polar to get access to their benefit. This is particularly problematic for Discord/GitHub benefits where an action is needed from them (connect their account) so we can fulfil the benefit.

Envisioned architecture

To solve those limitations, we'll introduce a Customer object, which is a dedicated layer at organization level to manage customers. This object will bear the orders, subscriptions and benefit grants.

flowchart TD
    C[Customer]
    U[User]
    ORG[Organization]
    O[Order]
    S[Subscription]
    BG[BenefitGrant]
    B[Benefit]
    O --> C
    S --> C
    BG --> C
    BG --> B
    C --> ORG
    B --> ORG
    C -.-> U
Loading

With this approach, we now have a dedicated layer manageable by an organization to create/read/update/delete customers without interfering with other data. It also allows to have those temporary customer sessions to retrieve benefits and manage orders.

This change has big impact on how we do things:

  • After a successful Checkout, a Customer object is created instead of a User
    • We'll also need the ability for a creator to pre-create the Customer and pass it down to the Checkout session.
  • Orders are linked to a Customer object
  • Subscriptions are linked to a Customer object
  • Benefits are granted at a Customer level

Benefit Grants is the most impactful one. However, it'll also solve some UX issues mentioned above. Typically, granting Discord/GitHub will always be a proactive move from the customer: instead of sending an error email prompting them to connect their Discord/GitHub account, they'll have a button in their customer portal to do so right after the order, which is way more expected.

In this new vision, we also see a User is no longer needed for customers: they can buy something, get their benefits with a customer's session and be done with it. Creating a user account will have the effect of linking all the Customers (across several organizations) with that email to that User, enabling the user to manage all their orders from a single place. In the future, we can also think of features to link customers with a different email to a User.

Migration challenges

Currently, Orders, Subscriptions and Benefit Grants API expose the user_id. It's probable that integrations have saved this user_id in their database to link Polar with their own app.

When we migrate this existing data to the new architecture, we'll generate Customer as needed and link them accordingly.

*Outdated migration approach* However, those Customer will have a new ID that doesn't correspond to the pre-existing user ID. To solve this we'll do the following:
  • We'll set the Customer ID to the ID of the originating user. For example, for User(id="ABC"), we'll create Customer(id="ABC")
  • In the API, we'll still expose user_id and add customer_id. For pre-existing customers, user_id will equal customer_id, ensuring integrations that saved those ID are still working.
  • Of course, for new customers, we'll generate new UUID and expose it both as user_id (for backward compatibility) and as customer_id.

The main limitation of this approach is for users that have made several purchases on different organizations. According to our data there are very few of them (<10). For those, we'll manually review their data and contact the organization owners so the migration happens smoothly.

See #4543 (comment) for the new approach

Planning

Those are major changes to our architecture, so this will probably take a few weeks of work to complete.

Architecture

  • Design and create Customer model
  • Make Checkout, Order, Subscriptions and Benefit Grants work with Customer instead of User
  • Revamp benefit granting logic for those requiring an action (Discord/GitHub).
  • Create a migration script to create Customer and link them accordingly to orders/subscriptions/grants
    • Remove BenefitPreconditionErrorNotification notifications
    • Move OAuth info to Customer oauth accounts (for Discord/GitHub benefits)
    • License key benefit properties: rename enable_user_admin to enable_customer_admin
    • Replace granular user scopes by customer portal scopes

API

  • Create an API to CRUD Customer
  • Update Orders/Subscriptions API to work with Customer
  • Accept to pass customer_id when creating Checkout session
  • Create an authentication mechanism for Customer (temporary sessions)
  • Make Customers API work for user authenticated requests + Transactions API
  • Create an API to update grant properties for benefit requiring action (Discord/GitHub)
  • When a User account is created, link Customers with the same emailΒ #4646

UI

  • Create a view to list, create and update customers
  • Revamp how customer portal is working using customer's sessions

Cleanups

Pre-deployment tasks

  • Add redirect URI to GitHub
  • Add redirect URI to Discord

Next steps

Implementing this is probably the last missing brick in building a complete and serious merchant of records software. This foundation will help us shaping future cool features like CRM-like data management, support management, invoicing, etc.

We Want Your Input

Help us shape the future of Polar's customer management. We're particularly interested in your thoughts on:

  • How might this new customer model impact your workflow?
  • Are there specific customer management features you need?
  • Do you see any potential challenges with this approach we might have missed?

Share your insights, suggestions, or questions in the comments below πŸ‘‡

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions