Browse Start

Protect a feature

Suppose exporting a report requires a paid plan. The user clicks Export; your app checks access, opens an upgrade offer if needed, refreshes access after checkout, and lets the server make the final decision about the export.

1. Prepare the offer and access check

  1. Publish an upgrade offer with the slug upgrade. Test its price and checkout flow.
  2. In your own authenticated app, expose a read endpoint such as /api/access/export that returns { "canExport": true } or { "canExport": false } for the current user. That route is your application code, not a Plandalf endpoint.
  3. Protect the actual export endpoint on your server. It must check the current customer's entitlement even if the browser says access is allowed. Arrange for confirmed purchases to update that entitlement record.

The examples below assume your access endpoint and purchase handoff are working. Replace https://your-org.plandalf.dev with your organization host.

2. Connect the feature button

If you can edit only HTML, have your server decide whether to render this upgrade button. The attribute opens checkout; it cannot check entitlement by itself.

upgrade.html
<script defer src="https://your-org.plandalf.dev/js/plandalf-sdk.js"></script>
<button data-plandalf-present="upgrade">
  Unlock export
</button>

Keep the export endpoint protected server-side, and refresh the page or access state after a confirmed purchase.

3. Verify denied, dismissed, and paid states

  1. As a user without access, click Export. The upgrade checkout should open. Dismiss it: export stays blocked.
  2. After confirming that the offer and integration are explicitly configured for sandbox use, complete a provider-supported test checkout. A mode: 'test' override can fall back to live for public visitors. If your confirmed-purchase handoff has not yet updated entitlement, keep access pending; do not hand over the report because checkout returned complete.
  3. After your server records access, click again. The gate should allow the action without reopening checkout, and the export endpoint must independently allow it.
  4. Test a failed access request. It should deny the action and show an error or retry state.

The checked-out SDK source reruns the gate check after sync; verify the installed package version before relying on that client behavior. The server authorization check is still required. A denied gate has already opened its fallback offer, so do not call present() again. See the complete feature example, gate(), and GateResult for the exact outcomes.

Feature detail