Skip to content

Map Polar products

A product mapping says which Polar product grants which of your Sealcord products, and on what terms. Map each Polar product you sell, in the Console on the product’s page, or with the Admin API. An order for a Polar product without a mapping issues nothing, and Sealcord tells you.

Field Default Meaning
product_id required Your Sealcord product, such as acme-notes
limit_kind seats seats or machines (which)
limit_count 1 How many. A seat-based order that carries its own seat count uses that count instead
key_valid_days none Put an expiry this many days (1 to 36500) after purchase in the key. None makes a perpetual key
on_refund revoke revoke ends the licence on a full refund of its order; none leaves it
on_subscription_end expire expire or revoke, what happens when the subscription ends
renewal_url none Where a customer renews, one of your Polar checkout links (rules)

A subscription’s key carries no expiry unless you set key_valid_days, because an embedded expiry would force a new key at every renewal. The subscription’s end is enforced online, through the verdict.

One Sealcord product can have several Polar products, such as monthly, yearly and lifetime, each with its own mapping and terms. A Polar product maps to one Sealcord product per integration.

Open the product, find its Polar products, and choose “Map a Polar product”: pick the integration, paste the Polar product’s id, then set the terms and optionally the renewal link. Saving checks the product with Polar. Owners and admins can change mappings.

With an admin API key that has polar:write:

Terminal window
curl -X PUT \
"https://api.sealcord.com/v1/admin/integrations/$INTEGRATION_ID/mappings/$POLAR_PRODUCT_ID" \
-H "authorization: Bearer $SEALCORD_TOKEN" \
-H 'content-type: application/json' \
-d '{
"product_id": "acme-notes",
"limit_kind": "machines",
"limit_count": 2,
"key_valid_days": null,
"on_refund": "revoke",
"on_subscription_end": "expire"
}'

$INTEGRATION_ID is the id the Console shows for the integration, or GET /v1/admin/integrations lists (scope polar:read); $POLAR_PRODUCT_ID is the product’s id in Polar. The answer is the mapping. GET /v1/admin/integrations/{id}/mappings lists an integration’s mappings and DELETE on the same path as the PUT removes one (204).

Saving a mapping asks Polar, with the integration’s token, whether the product exists in your Polar organization. It answers:

  • 400 validation_failed when Polar has no such product;
  • 404 product_not_found when the Sealcord product is not your organization’s;
  • 422 polar_token_invalid when Polar no longer accepts the token (a needs_attention integration’s usual cause) or the token lacks the products:read scope;
  • 404 integration_not_found when the integration is disconnected;
  • 502 polar_unavailable when Polar does not answer.

Every change is in your audit log. Mappings belong to one integration: another integration mapping the same Polar product changes nothing here. Routes and bodies are in the API reference.

A renewal_url is where a customer whose licence has expired goes to buy again. My licences offers it only on a licence whose key has an end, so a mapping without key_valid_days shows no renewal link. It must be one of your Polar checkout links, found in Polar under Products, Checkout Links, for the integration’s environment, over https:

Environment Accepted
Production https://buy.polar.sh/polar_cl_… or https://api.polar.sh/v1/checkout-links/polar_cl_…/redirect
Sandbox https://sandbox-api.polar.sh/v1/checkout-links/polar_cl_…/redirect

A query string, such as Polar’s prefill parameters, may follow. Any other URL, including Polar’s other pages, is refused with 400 validation_failed, so a customer never leaves Polar by this link. Sealcord stores the link as a browser reads it and adds nothing to it. Sending null removes it; leaving the field out keeps a saved one. A licence does not record which Polar product sold it, so when several mappings of its integration grant its product, the customer sees the first one that has a renewal link, by Polar product id.

What does a customer get when Polar has no mapping for what they bought?

Section titled “What does a customer get when Polar has no mapping for what they bought?”

Nothing is issued. Sealcord records the order as ignored and emails your organization’s owners and admins, at most once a day for each integration and reason. Add the mapping, then issue the customer’s licence by hand, from the Console or the Admin API: Sealcord does not issue that order later by itself.

Can one Polar product grant two Sealcord products?

Section titled “Can one Polar product grant two Sealcord products?”

A mapping names one Sealcord product. Map a bundle by issuing the second licence from your own backend, with the Admin API.

Does changing a mapping change licences already issued?

Section titled “Does changing a mapping change licences already issued?”

A licence already issued keeps its limit and its key. The mapping’s refund and subscription-end choices apply to events from then on, including events about licences issued before, and a new renewal link shows on them at once.