When someone logs in, Outseta gives them a JWT access token. The token says who they are, which account they're signed in to and which products that account owns. Your site can read it to decide what to show.

This article is for Outseta v3, where you sell products. On v3 the token lists products. It doesn't contain the v2 plan and add-on claims (outseta:planUid, outseta:addOnUids, outseta:subscriptionUid). If you've seen those in other examples, those examples are for v2.

Example payload (shortened):

{
  "sub": "...",
  "email": "[email protected]",
  "outseta:accountUid": "...",
  "outseta:isPrimary": "1",
  "outseta:productUids": ["dpWr7ZQn", "Lm4kX9aB"],
  "iat": 1761140000,
  "exp": 1761226400
}

The Outseta claims

Claim What it is
outseta:accountUid The account the person is signed in to.
outseta:accountClientIdentifier Your own identifier for the account. Only present if you've set one.
outseta:isPrimary "1" if the person is the account's primary contact, "0" if not. It's a string.
outseta:productUids A JSON array with the UIDs of the products the account owns right now. It's an empty array if they own none.

What counts as owning a product

  • Subscription products, while the subscription has started and is trialing, active or past due. If a customer cancels at the end of the billing period, they keep the product until the period ends. When the subscription ends, its products drop out of the list.
  • One-time products, from every paid invoice that hasn't been refunded. They stay in the list for good, even after a subscription ends. They're only removed if the purchase is refunded, or if you cancel access to that product on the account in the CRM.

If several subscriptions or purchases give the same product, it appears once.

People who aren't the primary contact

The primary contact gets every product the account owns. Other people on the account only get products whose Registration mode is Team. Products set to Individual don't appear in their token.

Logging in

On v3, people can log in whether or not they have an active subscription. Someone whose subscription has ended can still sign in and see the one-time products they bought. Their outseta:productUids just no longer includes the subscription's product.

When the token updates

The token is issued when the person logs in. After that, the Outseta script checks on page load whether the products in the token are still current. It checks at most once every five minutes per browser session, and fetches a new token automatically if they've changed. So a purchase, cancellation or refund shows up on a page load within a few minutes. Logging out and back in always gives a fresh token straight away.

Reading the token on your site

Outseta.getJwtPayload() returns the payload of the current token. To react when the token is set or replaced, listen for accessToken.set. It also runs straight away if the person is already logged in:

Outseta.on("accessToken.set", function (payload) {
  var products = payload["outseta:productUids"] || [];
  if (products.includes("dpWr7ZQn")) {
    // show the content for this product
  }
});

Outseta's no-code content protection (content groups and the protection settings on your pages) reads outseta:productUids for you. You only need code like this for custom logic.

Through the API

  • CurrentStripeProductInstances on the account (for example GET /api/v1/crm/accounts/{accountUid} with your API key) lists the same products. It's the whole account's list, without the Team filter described above. Account webhooks and the "Account Current Products" segment condition use the same list.
  • To see which subscription gives which product, look at the account's StripeSubscriptions. Each one has StripeSubscriptionItems, and each item's StripePrice.StripeProduct.Uid is the product. Status, CancelAtPeriodEnd, CancelAt and EndedAt tell you the subscription's state. You don't need these for access control, because outseta:productUids already applies the rules above.
  • CurrentSubscription and the v2 subscription fields are empty on v3. That's expected.